Пример #1
0
 def __init__(self):
     self.name = 'TVDbExtension'
     self.tvdb = tvdb_api.Tvdb(actors=True)
     self.supported_fflags = [fflags.SHOW_FLAG, fflags.SHOW_DIRECTORY_FLAG]
     self.supported_season_fflags = [fflags.SEASON_DIRECTORY_FLAG]
     self.supported_subtitle_fflags = []
Пример #2
0
 def setup_class(cls):
     if cls.t is None:
         cls.t = tvdb_api.Tvdb(cache=get_test_cache_session(), banners=False)
Пример #3
0
 def test_episode_name_spanish(self):
     """Check episode data is in Spanish (language="es")
     """
     t = tvdb_api.Tvdb(cache=get_test_cache_session(), language="es")
     assert t['scrubs'][1][1]['episodeName'] == u'Mi primer día'
     assert t['scrubs']['overview'].startswith(u'Scrubs es una divertida comedia')
Пример #4
0
    def setUp(self):
        if self.t_dvd is None:
            self.t_dvd = tvdb_api.Tvdb(cache=True, useZip=True, dvdorder=True)

        if self.t_air is None:
            self.t_air = tvdb_api.Tvdb(cache=True, useZip=True)
Пример #5
0
 def setUp(self):
     if self.t is None:
         self.__class__.t = tvdb_api.Tvdb(cache=True, banners=False)
Пример #6
0
########################################################
########################################################

cartoonsLeft = cartoons.copy()
showDirectory = []
commercialList = []
commercialSpecific = {}
previousRandomShow = 999
playlistDuration = 0
showDurations = []
showName = ""
showDesc = ""
showCounter = 0
showLength = 0
blockCounter = 0
t = tvdb_api.Tvdb()


extensions = ['.264', '.3g2', '.3gp', '.3gp2', '.3gpp', '.3gpp2', '.3mm', '.3p2', '.60d', '.787', '.89', '.aaf', '.aec', '.aep', '.aepx',
              '.aet', '.aetx', '.ajp', '.ale', '.am', '.amc', '.amv', '.amx', '.anim', '.aqt', '.arcut', '.arf', '.asf', '.asx', '.avb',
              '.avc', '.avd', '.avi', '.avp', '.avs', '.avs', '.avv', '.axm', '.bdm', '.bdmv', '.bdt2', '.bdt3', '.bik', '.bin', '.bix',
              '.bmk', '.bnp', '.box', '.bs4', '.bsf', '.bvr', '.byu', '.camproj', '.camrec', '.camv', '.ced', '.cel', '.cine', '.cip',
              '.clpi', '.cmmp', '.cmmtpl', '.cmproj', '.cmrec', '.cpi', '.cst', '.cvc', '.cx3', '.d2v', '.d3v', '.dat', '.dav', '.dce',
              '.dck', '.dcr', '.dcr', '.ddat', '.dif', '.dir', '.divx', '.dlx', '.dmb', '.dmsd', '.dmsd3d', '.dmsm', '.dmsm3d', '.dmss',
              '.dmx', '.dnc', '.dpa', '.dpg', '.dream', '.dsy', '.dv', '.dv-avi', '.dv4', '.dvdmedia', '.dvr', '.dvr-ms', '.dvx', '.dxr',
              '.dzm', '.dzp', '.dzt', '.edl', '.evo', '.eye', '.ezt', '.f4p', '.f4v', '.fbr', '.fbr', '.fbz', '.fcp', '.fcproject', '.ffd',
              '.flc', '.flh', '.fli', '.flv', '.flx', '.gfp', '.gl', '.gom', '.grasp', '.gts', '.gvi', '.gvp', '.h264', '.hdmov', '.hkm',
              '.ifo', '.imovieproj', '.imovieproject', '.ircp', '.irf', '.ism', '.ismc', '.ismv', '.iva', '.ivf', '.ivr', '.ivs', '.izz',
              '.izzy', '.jss', '.jts', '.jtv', '.k3g', '.kmv', '.ktn', '.lrec', '.lsf', '.lsx', '.m15', '.m1pg', '.m1v', '.m21', '.m21',
              '.m2a', '.m2p', '.m2t', '.m2ts', '.m2v', '.m4e', '.m4u', '.m4v', '.m75', '.mani', '.meta', '.mgv', '.mj2', '.mjp', '.mjpg',
              '.mk3d', '.mkv', '.mmv', '.mnv', '.mob', '.mod', '.modd', '.moff', '.moi', '.moov', '.mov', '.movie', '.mp21', '.mp21',
Пример #7
0
    def populate(self, config):
        import tvdb_api

        image_cache = config["image_cache"]

        tvdb = tvdb_api.Tvdb(apikey=THETVDB_APIKEY, banners=True)
        identifier = int(self.identifier)
        tv_show = tvdb[identifier]

        if tv_show.data["seriesName"] == "** 403: Series Not Permitted **":
            return

        self.genres.clear()

        self.network = None
        self.content_rating = None
        self.primary_language = None
        self.status = None
        self.imdb_id = None

        self.title = tv_show.data["seriesName"]
        self.rating = tv_show.data["siteRating"]
        self.votes = tv_show.data["siteRatingCount"]
        self.duration = tv_show.data["runtime"]

        if tv_show.data.get("imdb_id"):
            imdb_id = re.findall("tt(\d+)", tv_show.data["imdbId"])
            if imdb_id:
                self.imdb_id = imdb_id[0]

        self.year = None
        if tv_show.data.get("firstAired"):
            self.year = tv_show.data.get("firstAired").split("-")[0]

        self.synopsis = tv_show.data["overview"]

        if (tv_show.data.get("_banners", {}).get(
                "poster", {}).get("raw")):  # this is retarded design
            posters = sorted(
                tv_show.data["_banners"]["poster"]["raw"],
                key=lambda x: x["ratingsInfo"]["count"],
            )
            if posters:
                best_id = posters[-1]["id"]
                for _, v in tv_show.data["_banners"]["poster"].items():
                    if best_id in v:
                        self.cover = v[best_id]["_bannerpath"]
                        image_cache.get_image_path(self.cover)
                        break

        if tv_show.data.get("network"):
            self.network, _ = Network.objects.get_or_create(
                name=tv_show.data["network"])

        if tv_show.data.get("rating"):
            self.content_rating, _ = ContentRating.objects.get_or_create(
                name=tv_show.data["rating"])

        if tv_show.data.get("language"):
            self.primary_language, _ = Language.objects.get_or_create(
                name=tv_show.data["language"])

        if tv_show.data.get("status"):
            self.status, _ = Status.objects.get_or_create(
                name=tv_show.data["status"])

        if tv_show.data["genre"]:
            for genre in tv_show.data["genre"]:
                genre, _ = Genre.objects.get_or_create(name=genre)
                self.genres.add(genre)

        Episode.objects.filter(metadata=self).delete()

        for season, episodes in tv_show.items():
            for episode, episode_info in episodes.items():
                e = Episode(metadata=self, season=season, episode=episode)
                e.title = episode_info["episodeName"]
                if episode_info.get("firstAired"):
                    e.air_date = date(*[
                        int(x) for x in episode_info["firstAired"].split("-")
                    ])

                e.save()
Пример #8
0
#richiedere una password senza visualizzarla
from getpass import getpass
getpass("messaggio da mostrare")

#Elencare i file in una cartella
a = os.listdir(os.path.expanduser("~/Media/Film"))
b = []
for i in a:
    b.append(i.split('.')[0])  #Elimino le estensioni

######
#TvDB#
######
#Utilizzo di TvDB per ottenere le info sulle serie tv
import tvdb_api as tvdb
t = tvdb.Tvdb(language='it')  #Setto la lingua italiana

a = os.listdir(os.path.expanduser("~/Media/Serie TV"))
t['Adventure Time']

for i in a:
    try:
        print i + str(t[i][1][5])
    except:
        print "ERROR %s" % i

t['bobs burgers']
t['i simpson'].search("La Paura Fa Novanta", key='episodename')
t['i simpson'].search("Gli Piace Volare E D'oh Lo Fa", key='episodename')
t['i simpson'].search("Gli Piace Volare", key='episodename')
Пример #9
0
 def __init__(self, interactive=True):
     self.tvdb = tvdb_api.Tvdb(interactive=interactive,
                               banners=True,
                               actors=True,
                               apikey=d(api_key))
Пример #10
0
def resolve_episode_ids(series, season, episode, year=None, imdbid=None):
    # To store the IDs found
    ids = {}

    # Initialize a TMDB search object
    tmdb_search = tmdbsimple.Search()

    ##################################################################
    # TVDB
    tvdb = tvdb_api.Tvdb(language='en', )

    tvdb_series = None
    try:
        # Try getting the series directly, but check the year if available
        # as sometimes series have the same name but are from different years
        tvdb_series = tvdb[series]
        if (imdbid is None or tvdb_series['imdbId'] != imdbid) and \
                year is not None and tvdb_series['firstAired'] and \
                year != int(tvdb_series['firstAired'].split('-')[0]):
            # It is not the expected year, we thus need to perform a search
            tvdb_series = None
            tvdb_search = tvdb.search(series)
            for s in tvdb_search:
                if imdbid is None or s['imdbId'] != imdbid:
                    if not s['seriesName'].startswith(series):
                        LOGGER.debug('TVDB: Discarding result because of the '
                                     'name not beginning with the expected '
                                     'series name: {}'.format(s))
                        continue

                    if int(s['firstAired'].split('-')[0]) != year:
                        LOGGER.debug('TVDB: Discarding result because of the '
                                     'year not matching: {}'.format(s))
                        continue

                tvdb_series = tvdb[s['seriesName']]
                break

        tvdb_season = tvdb_series[season]
        tvdb_episode = tvdb_season[episode]
        ids['tvdb'] = tvdb_episode['id']
    except Exception as e:
        LOGGER.debug(e)
        LOGGER.warning('Unable to find series {}, season {}, '
                       'episode {} on TheTVDB'.format(series, season, episode))

    ##################################################################
    # TMDB
    params = {'query': series}
    if year is not None:
        params['first_air_date_year'] = year

    try:
        tmdb_search.tv(**params)
    except Exception as e:
        LOGGER.debug(e)
        tmdb_search.results = []

    for s in tmdb_search.results:
        if s['name'] != series and \
                (tvdb_series is None or
                 (s['name'] != tvdb_series['seriesName'] and
                  s['name'] not in tvdb_series['aliases'])):
            LOGGER.debug('TMDB: Discarding result because of the name '
                         'not matching with the expected series '
                         'name: {}'.format(s))
            continue

        # Try to get the episode information
        tmdb_episode = tmdbsimple.TV_Episodes(s['id'], season, episode)
        try:
            tmdb_external_ids = tmdb_episode.external_ids()
        except Exception as e:
            continue

        # If we have the tvdb information, check that we got the right
        # id... else, it is probably not the episode we are looking
        # for!
        if 'tvdb' in ids and \
                tmdb_external_ids.get('tvdb_id') is not None and \
                ids['tvdb'] != tmdb_external_ids['tvdb_id']:
            LOGGER.debug('TMDB: Discarding result because of the TVDB id not '
                         'matching with the one found on the TVDB '
                         'side: {}'.format(s))
            continue

        ids['tmdb'] = tmdb_external_ids['id']
        break

    return ids
Пример #11
0
 def __init__(self):
     super(TTVDBScanner, self).__init__()
     self.web_api = tvdb_api.Tvdb(apikey="5BA46DFDB0AB740E",
                                  actors=True,
                                  banners=True,
                                  language='fr')
Пример #12
0
def main():
    parser = argparse.ArgumentParser()
    # TODO support sources as wildcards
    parser.add_argument('sources',
                        type=cli.argparse_path,
                        nargs='+',
                        help='paths to source directories/files')
    parser.add_argument('dst',
                        type=cli.argparse_path,
                        help='path to destination directory')

    # TODO add argument groups
    parser.add_argument('-vk',
                        default=False,
                        action='store_true',
                        help='keep source video')
    parser.add_argument('-vr',
                        default=False,
                        action='store_true',
                        help='recode video')
    parser.add_argument('-vc',
                        choices=VideoCodec.get_names(
                            [VideoCodec.H264, VideoCodec.H265]),
                        default=VideoCodec.H264.name,
                        help='set video encoding codec')
    add_enum_argument(parser, '-vt', InputTune, None,
                      'set video encoding tune')
    add_enum_argument(parser, '-vq', InputQuality, None,
                      'set video encoding quality')
    parser.add_argument('-va',
                        default=None,
                        choices=['16:9'],
                        help='set video display aspect ratio')
    parser.add_argument('-vs',
                        default=None,
                        choices=['720p', '1080p', '1440p'],
                        help='scale video')
    parser.add_argument('-ks',
                        default=False,
                        action='store_true',
                        help='keep current colorspace')

    parser.add_argument('-cr',
                        default=False,
                        action='store_true',
                        help='crop video')
    parser.add_argument('-cf',
                        type=cli.argparse_path,
                        default=None,
                        metavar='<path>',
                        help='path to crop map file')
    parser.add_argument('-sc',
                        default=False,
                        action='store_true',
                        help='use same crop values for all files')

    parser.add_argument(
        '-al',
        nargs='*',
        type=cli.argparse_lang,
        default=[],
        metavar='lang',
        help='ordered list of audio 3-letter language codes to keep')
    parser.add_argument('-ar',
                        default=False,
                        action='store_true',
                        help='recode audio')
    parser.add_argument('-ad',
                        default='5.1',
                        choices=CHANNEL_SCHEMES.keys(),
                        help='downmix to N channels')
    parser.add_argument('-aw',
                        default=False,
                        action='store_true',
                        help='convert audio to wavfile before encoding')

    parser.add_argument(
        '-sl',
        nargs='*',
        type=cli.argparse_lang,
        default=[],
        metavar='lang',
        help='ordered list of full subtitle 3-letter language codes to keep')
    parser.add_argument(
        '-fl',
        nargs='*',
        type=cli.argparse_lang,
        default=[],
        metavar='lang',
        help='ordered list of forced subtitle  3-letter language codes to keep'
    )
    parser.add_argument('-fo',
                        default=False,
                        action='store_true',
                        help='make forced subtitles optional')

    parser.add_argument('-nf',
                        type=cli.argparse_path,
                        default=None,
                        metavar='<path>',
                        help='path to names map file')
    parser.add_argument('-tv',
                        default=None,
                        metavar='<name>',
                        help='TV series name')
    parser.add_argument('-il',
                        default=False,
                        action='store_true',
                        help='Ignore track language data')
    parser.add_argument('-xx',
                        default=False,
                        action='store_true',
                        help='Remove original files after processing')
    parser.add_argument('-ma',
                        default=False,
                        action='store_true',
                        help='Append mux file instead of overwrite')
    parser.add_argument('-ds',
                        default=False,
                        action='store_true',
                        help='Disable movie sattelites detection')
    parser.add_argument('-sd',
                        default=False,
                        action='store_true',
                        help='Securely delete files using sdelete utility')

    args = parser.parse_args()
    if args.cf and args.sc:
        parser.error(u'Use -cf or -sc, not both')
    if args.nf and args.tv:
        parser.error(u'Use -nf or -tv, not both')
    if args.vk and (args.vr or args.vt):
        parser.error(u'Use -vk or -vr/-vt, not both')
    if not args.vk and (not args.vt or not args.vq):
        parser.error(u'Set -vt and -vq')

    args.vc = VideoCodec.get_definition(args.vc)
    if args.vt:
        args.vt = InputTune.get_definition(args.vt)
    if args.vq:
        args.vq = InputQuality.get_definition(args.vq)

    def read_movie_path(path):
        path = os.path.normpath(path.strip())
        if is_media_file_path(path):
            path = os.path.splitext(path)[0]
        return path

    def read_crop_args(s):
        s = s.strip()
        if s.lower() == 'no':
            return False
        return [int(x) for x in s.split(':')]

    filenames_map = read_map_file(args.nf, read_movie_path, read_movie_path)
    raw_crops_map = read_map_file(args.cf, read_movie_path, read_crop_args)

    tvdb = None
    if args.tv:
        tvdb = tvdb_api.Tvdb()

    movies = {}
    crop_args_map = None if raw_crops_map is None else {}
    for argspath in args.sources:
        for movie_object in find_movies(argspath, args.il, not args.ds):
            cur_path = os.path.normpath(
                os.path.relpath(movie_object.main_path(), platform.getcwd()))
            if raw_crops_map is not None:
                crop_args_map[movie_object.main_path()] = raw_crops_map[
                    os.path.splitext(cur_path)[0]]
            if args.tv:
                movie_name = os.path.basename(movie_object.main_path())
                src_season = int(
                    re.match(r'.*s(\d+)', movie_name, re.IGNORECASE).group(1))
                src_episodes = [
                    int(x)
                    for x in re.findall(r'e(\d+)', movie_name, re.IGNORECASE)
                ]
                ep_numbers = []
                ep_names = set()
                for src_episode in src_episodes:
                    ep_info = tvdb[args.tv][src_season][src_episode]
                    epn_dvd = ep_info['dvdEpisodeNumber']
                    epn_air = ep_info['airedEpisodeNumber']
                    if epn_dvd is not None and epn_dvd != epn_air:
                        epn_dvd_int = int(float(epn_dvd))
                        epn_dvd_frc = float(epn_dvd) - epn_dvd_int
                        assert int(epn_air) == int(
                            round(epn_dvd_int +
                                  (epn_dvd_frc - 0.1) * 10)), 'd{} a{}'.format(
                                      epn_dvd, epn_air)
                    ep_numbers.append(int(epn_air))
                    ep_names.add(
                        re.sub(r'\(\d\)$', '', ep_info['episodename']).strip())
                assert len(ep_numbers) > 0 and len(ep_names) == 1, ep_names
                cur_path = u'{} {}.mkv'.format(
                    '-'.join(u'{:02d}'.format(epn)
                             for epn in sorted(ep_numbers)),
                    list(ep_names)[0])
            elif filenames_map is not None:
                raw_new_name_string = filenames_map[os.path.splitext(cur_path)
                                                    [0]]
                cur_path = None
                if raw_new_name_string == 'NO': continue
                elif raw_new_name_string == 'KEEP': cur_path = cur_path
                else: cur_path = raw_new_name_string
            if is_media_file_path(cur_path):
                cur_path = os.path.splitext(cur_path)[0]
            new_name = u'{}.mkv'.format(
                platform.clean_filename(os.path.basename(cur_path)))
            new_path = os.path.join(os.path.abspath(args.dst),
                                    os.path.dirname(cur_path), new_name)
            assert new_path not in movies, new_path
            movies[new_path] = movie_object

    output_track_specs = collections.OrderedDict([
        ((TrackType.VID, False), ['und']),
        ((TrackType.AUD, False), args.al),
        ((TrackType.SUB, False), args.sl),
        ((TrackType.SUB, True), args.fl),
    ])

    if not (args.ma and os.path.isfile(MUX_BODY)):
        try:
            os.remove(MUX_BODY)
        except:
            pass
        shutil.copyfile(MUX_HEAD, MUX_BODY)

    created_directories = set()
    # TODO catch some of my exceptions, report skipped file, ask for action, log skipped file
    common_crop_args = None
    for target_path, movie in sorted(movies.iteritems(),
                                     key=lambda m: m[1].main_path()):
        platform.print_string(u'=== {} ==='.format(movie.main_path()))
        output_tracks = {}
        for (track_type, _) in output_track_specs.iterkeys():
            output_tracks[track_type] = []
        used_tracks = set()
        reference_duration = movie.reference_duration() or 0
        duration_threshold = reference_duration / 100.0 * 20.0
        for (track_type,
             search_forced), lang_list in output_track_specs.iteritems():
            forced_string = 'Forced' if search_forced else 'Full'
            for target_lang in lang_list:
                candidates = {}
                for track in movie.tracks(track_type):
                    if track.qualified_id() in used_tracks: continue
                    if track.language() not in (
                            target_lang, 'und') and target_lang != 'und':
                        continue
                    if any(s in track.name().lower()
                           for s in [u'comment', u'коммент']):
                        continue
                    if track.is_forced() is not None:
                        if track.is_forced() != search_forced: continue
                        if not track.is_forced() and track.duration(
                        ) is not None:
                            if reference_duration - track.duration(
                            ) > duration_threshold:
                                continue
                    candidates[track.qualified_id()] = track
                if not candidates:
                    if search_forced and args.fo: continue
                    raise cli.Error(u'{} {} {} not found'.format(
                        forced_string, track_type, target_lang))

                chosen_track_id = None
                if len(candidates) == 1:
                    chosen_track_id = list(candidates.keys())[0]

                sorted_candidates = sorted(candidates.itervalues(),
                                           key=lambda t: t.qualified_id())
                if chosen_track_id not in candidates:
                    candidates_by_index = {}
                    for track in sorted_candidates:
                        candidates_by_index[movie.track_index_in_type(
                            track)] = track.qualified_id()
                    header = u'--- {}, {}, {} ---'.format(
                        track_type, target_lang.upper(), forced_string)
                    # TODO if tv AND if tracks ids, names and codecs same as before then choose track automatically
                    chosen_track_index = ask_to_select_tracks(
                        movie, track_type, sorted_candidates, header)
                    chosen_track_id = candidates_by_index[chosen_track_index]

                used_tracks.add(chosen_track_id)
                chosen_track = candidates[chosen_track_id]
                chosen_track.set_language(target_lang)
                chosen_track.set_forced(search_forced)
                output_tracks[track_type].append(chosen_track)

        assert len(output_tracks[TrackType.VID]) == 1
        video_track = output_tracks[TrackType.VID][0]

        def track_sort_key(t):
            lng_idx = output_track_specs[(t.type(),
                                          t.is_forced())].index(t.language())
            return lng_idx + 1000 * int(t.is_forced())

        track_sources = {}
        for track_type, track_list in output_tracks.iteritems():
            track_list.sort(key=track_sort_key)
            for track in track_list:
                track_sources[track.qualified_id()] = [
                    track.source_file(), track.id()
                ]

        result_commands = [u'echo {}'.format(cmd.quote(movie.main_path()))]
        mux_temporary_files = []

        target_directory = os.path.dirname(target_path)
        if not os.path.isdir(target_directory
                             ) and target_directory not in created_directories:
            result_commands.extend(cmd.gen_create_dir(target_directory))
            created_directories.add(target_directory)

        def make_single_track_file(track,
                                   stream_id,
                                   file_ext=None,
                                   ffmpeg_opts=None,
                                   prefer_ffmpeg=True):
            if file_ext is None:
                file_ext = track.get_single_track_file_extension()
            if ffmpeg_opts is None:
                ffmpeg_opts = ['-c:{} copy'.format(stream_id)]
            if file_ext == platform.file_ext(
                    track.source_file()) and track.is_single():
                return track.source_file(), False
            tmp_path = platform.make_temporary_file(file_ext)
            if not prefer_ffmpeg and platform.file_ext(
                    track.source_file()) == '.mkv':
                command = cmd.gen_mkvtoolnix_extract_track(
                    track.source_file(), tmp_path, track.id())
            else:
                command = cmd.gen_ffmpeg_extract_track(track.source_file(),
                                                       tmp_path, track.id(),
                                                       [], ffmpeg_opts)
            result_commands.extend(command)
            return tmp_path, True

        # TODO move to software abstraction
        source_container_supported_by_mkvmerge = video_track.container_format(
        ) not in {FileFormat.x3GP, FileFormat.SMK, FileFormat.WMV}

        source_video_codec = video_track.codec()
        source_video_crf = video_track.crf()
        source_video_profile = video_track.profile()
        source_video_level = video_track.level()

        target_video_codec = args.vc
        target_video_profile, target_video_level = CODEC_FFMPEG_PARAMETERS[
            target_video_codec]

        encoded_ok = source_video_codec == target_video_codec and \
            source_video_crf is not None and \
            source_video_profile == target_video_profile and \
            source_video_level == target_video_level
        if args.vr or args.vs or not encoded_ok and not args.vk:
            ffmpeg = Ffmpeg()
            target_crf, target_tune = CODEC_TUNES[target_video_codec][args.vt][
                args.vq]

            # TODO check out rutracker manuals for dvd rip filters and stuff
            ffmpeg_filters = []

            assert video_track.field_order() is not None
            if video_track.field_order() in (FieldOrder.INTERLACED_BOT,
                                             FieldOrder.INTERLACED_TOP):
                # TODO consider bwdif
                ffmpeg_filters.append('yadif=1:-1:1')

            if args.va:
                ffmpeg_filters.append('setdar=dar={}'.format(args.va))

            crop_args = None
            if args.cr or args.cf:
                if common_crop_args is not None:
                    crop_args = common_crop_args
                if crop_args_map is not None:
                    crop_args = crop_args_map[video_track.source_file()]
                if crop_args is None:
                    os.system('ffmpegyag')
                    while crop_args is None:
                        try:
                            crop_args = [
                                int(x) for x in raw_input(
                                    'Enter crop parameters (w:h:x:y): ').strip(
                                    ).split(':')
                            ]
                        except:
                            pass
                    if args.sc:
                        common_crop_args = crop_args
            if crop_args is None or not crop_args:
                crop_args = [video_track.width(), video_track.height(), 0, 0]
            dw, dh, dx, dy = crop_args
            if not VideoTrack.dimensions_correct(dw, dh):
                platform.print_string(u'Adjusting crop by {}x{}'.format(
                    dw % 16, dh % 8))
                dw, dh, dx, dy = VideoTrack.correct_dimensions(dw, dh, dx, dy)
            assert VideoTrack.dimensions_correct(dw, dh)
            if dx > 0 or dy > 0 or dw != video_track.width(
            ) or dh != video_track.height():
                ffmpeg_filters.append('crop={w}:{h}:{x}:{y}'.format(w=dw,
                                                                    h=dh,
                                                                    x=dx,
                                                                    y=dy))

            # TODO support different resolutions
            # TODO forbid upscale
            if args.vs == '720p':
                ffmpeg_filters.append('scale=1280:-8')
            elif args.vs == '1080p':
                ffmpeg_filters.append('scale=1920:-8')
            elif args.vs == '1440p':  # TODO !!!!!!!!!!
                ffmpeg_filters.append('scale=-16:1440')

            src_colors = video_track.colors()
            dst_color_space = src_colors.correct_space()
            if args.ks:
                dst_color_space = src_colors.space()
            if src_colors.space() != dst_color_space:
                raise cli.Error(
                    u'Colorspace conversion from {} to {} not implemented'.
                    format(src_colors.space(), dst_color_space))
                # TODO specify input/output color_range
                # TODO specify each input component separately
                # TODO The input transfer characteristics, color space, color primaries and color range should be set on the input data
                # TODO clarify iall=all= format string
                # ffmpeg_filters.append('colorspace=iall={}:all={}'.format(src_color_space, dst_color_space))

            ffmpeg_src_options = []

            src_colors_range = src_colors.range()
            if src_colors_range is not None:
                ffmpeg_src_options.append('-color_range {}'.format(
                    ffmpeg.build_color_range_argument(src_colors_range)))

            ffmpeg_dst_options = ['-an', '-sn', '-dn']
            if ffmpeg_filters:
                ffmpeg_dst_options.append('-filter:v {}'.format(
                    ','.join(ffmpeg_filters)))
            ffmpeg_dst_options.extend([
                '-c:v {}'.format(
                    ffmpeg.build_video_encoding_library_argument(
                        target_video_codec)),
                '-preset veryslow',
                '-pix_fmt {}'.format(
                    ffmpeg.build_picture_format_argument(
                        PictureFormat.YUV420P)),
                '-crf {}'.format(target_crf),
                '-map_metadata -1',
                '-map_chapters -1',
            ])

            arg_profile = ffmpeg.build_video_codec_profile_argument(
                target_video_codec, target_video_profile)
            arg_level = ffmpeg.build_video_codec_level_argument(
                target_video_codec, target_video_level)
            if target_video_codec == VideoCodec.H264:
                ffmpeg_dst_options.extend([
                    '-profile:v {}'.format(arg_profile),
                    '-level:v {}'.format(arg_level)
                ])
            elif target_video_codec == VideoCodec.H265:
                ffmpeg_dst_options.append(
                    '-x265-params "profile={}:level={}"'.format(
                        arg_profile, arg_level))

            if target_tune is not None:
                ffmpeg_dst_options.append('-tune {}'.format(target_tune))

            if dst_color_space is not None and (
                    video_track.is_hd() or src_colors.space() is not None):
                ffmpeg_dst_options.extend([
                    # TODO "16-235 is a typical NTSC luma range. PAL always uses 0-255 luma range."
                    '-color_range {}'.format(
                        ffmpeg.build_color_range_argument(src_colors.range())),
                    '-color_primaries {}'.format(
                        ffmpeg.build_color_primaries_argument(
                            dst_color_space)),
                    '-color_trc {}'.format(
                        ffmpeg.build_color_trc_argument(dst_color_space)),
                    '-colorspace {}'.format(
                        ffmpeg.build_color_space_argument(dst_color_space)),
                ])
            else:
                assert not video_track.is_hd()

            new_video_path = platform.make_temporary_file('.mkv')
            result_commands.extend(
                cmd.gen_ffmpeg_convert(video_track.source_file(),
                                       ffmpeg_src_options, new_video_path,
                                       ffmpeg_dst_options))
            track_sources[video_track.qualified_id()] = [new_video_path, 0]
            mux_temporary_files.append(new_video_path)
        elif not source_container_supported_by_mkvmerge:
            new_video_path, _ = make_single_track_file(
                video_track, Ffmpeg.STREAM_ARGUMENT_VID, '.mkv')
            track_sources[video_track.qualified_id()] = [new_video_path, 0]
            mux_temporary_files.append(new_video_path)

        # TODO move to software abstraction
        audio_codecs_to_denorm = {AudioCodec.AC3, AudioCodec.DTS}
        audio_codecs_to_uncompress = {
            AudioCodec.AAC_HE,
            AudioCodec.AAC_HE_V2,
            AudioCodec.AAC_LC,
            AudioCodec.AMR,
            AudioCodec.OPUS,
            AudioCodec.SPEEX,
            AudioCodec.COOK,
            AudioCodec.ASAO,
            AudioCodec.ADPCM_SWF,
            AudioCodec.PCM_MULAW,
            AudioCodec.PCM_S16B,
            AudioCodec.VORBIS,
            AudioCodec.SMK,
            AudioCodec.WMA_PRO,
            AudioCodec.WMA_V2,
        }
        audio_codecs_to_recode = {
            AudioCodec.AMR, AudioCodec.ASAO, AudioCodec.OPUS, AudioCodec.SPEEX,
            AudioCodec.COOK, AudioCodec.EAC3, AudioCodec.DTS_ES,
            AudioCodec.DTS_HRA, AudioCodec.DTS_MA, AudioCodec.TRUE_HD,
            AudioCodec.ADPCM_IMA, AudioCodec.ADPCM_MS, AudioCodec.ADPCM_SWF,
            AudioCodec.PCM_MULAW, AudioCodec.PCM_S16B, AudioCodec.PCM_S16L,
            AudioCodec.PCM_S24L, AudioCodec.FLAC, AudioCodec.MP2,
            AudioCodec.VORBIS, AudioCodec.SMK, AudioCodec.WMA_PRO,
            AudioCodec.WMA_V2
        }

        max_audio_channels = CHANNEL_SCHEMES[args.ad]
        for track in output_tracks[TrackType.AUD]:
            need_extract = not source_container_supported_by_mkvmerge
            need_denorm = track.codec() in audio_codecs_to_denorm
            need_downmix = track.channels() > max_audio_channels
            need_recode = need_downmix or track.codec(
            ) in audio_codecs_to_recode or args.ar and track.codec(
            ) != AudioCodec.AAC_LC
            need_uncompress = track.codec(
            ) in audio_codecs_to_uncompress or args.aw

            if need_extract or need_denorm or need_downmix or need_recode:

                stf_ext = None
                stf_ffmpeg_opts = None
                if need_uncompress:
                    stf_ext = '.wav'
                    stf_ffmpeg_opts = ['-f wav', '-rf64 auto']
                src_track_file, is_src_track_file_temporary = make_single_track_file(
                    track, Ffmpeg.STREAM_ARGUMENT_AUD, stf_ext,
                    stf_ffmpeg_opts)

                eac_track_file = src_track_file
                if need_denorm or need_downmix or need_recode:
                    eac_track_file = platform.make_temporary_file(
                        '.wav' if need_recode else platform.
                        file_ext(src_track_file))
                    eac_opts = []
                    if need_downmix:
                        if max_audio_channels == 1:
                            pass  # will be processed later
                        elif max_audio_channels == 2:
                            eac_opts.append('-downStereo')
                        elif max_audio_channels == 6:
                            eac_opts.append('-down6')
                        else:
                            raise cli.Error(
                                u'Unhandled channels num {}'.format(
                                    max_audio_channels))
                    if track.delay() != 0:
                        eac_opts.append('{}{}ms'.format(
                            '+' if track.delay() > 0 else '-',
                            abs(track.delay())))
                    result_commands.append(u'call eac3to {} {} {}'.format(
                        cmd.quote(src_track_file), cmd.quote(eac_track_file),
                        ' '.join(eac_opts)))
                    if is_src_track_file_temporary:
                        result_commands.extend(
                            cmd.gen_del_files(args.sd, src_track_file))

                dst_track_file = eac_track_file
                if need_downmix and max_audio_channels == 1:
                    mono_track_file = platform.make_temporary_file('.wav')
                    result_commands.extend(
                        cmd.gen_ffmpeg_convert(eac_track_file, [],
                                               mono_track_file, ['-ac 1']))
                    result_commands.extend(
                        cmd.gen_del_files(args.sd, eac_track_file))
                    dst_track_file = mono_track_file

                if need_recode:
                    m4a_track_file = platform.make_temporary_file('.m4a')
                    qaac_opts = [
                        '--tvbr 91', '--quality 2', '--rate keep', '--no-delay'
                    ]
                    qaac = u'qaac64 {} {} -o {}'.format(
                        u' '.join(qaac_opts), cmd.quote(dst_track_file),
                        cmd.quote(m4a_track_file))
                    result_commands.append(qaac)
                    result_commands.extend(
                        cmd.gen_del_files(args.sd, dst_track_file))
                    dst_track_file = m4a_track_file

                mux_temporary_files.append(dst_track_file)
                track_sources[track.qualified_id()] = [dst_track_file, 0]

        for track in output_tracks[TrackType.SUB]:
            if track.is_text():
                ffmpeg_opts = None
                if track.codec() == SubtitleCodec.MOV:
                    ffmpeg_opts = []
                track_file, is_track_file_temporary = make_single_track_file(
                    track, Ffmpeg.STREAM_ARGUMENT_SUB, ffmpeg_opts=ffmpeg_opts)
                srt_file = platform.make_temporary_file('.srt')
                result_commands.append(
                    u'{python} {script} {src_path} {dst_path}'.format(
                        python=sys.executable,
                        script=cmd.quote(
                            os.path.join(os.path.dirname(__file__),
                                         'any2srt.py')),
                        src_path=cmd.quote(track_file),
                        dst_path=cmd.quote(srt_file)))
                track_sources[track.qualified_id()] = [srt_file, 0]
                track.set_encoding(lang.norm_encoding('utf-8'))
                mux_temporary_files.append(srt_file)
                if is_track_file_temporary:
                    result_commands.extend(
                        cmd.gen_del_files(args.sd, track_file))
            elif track.codec() == SubtitleCodec.PGS:
                track_file, is_track_file_temporary = make_single_track_file(
                    track, Ffmpeg.STREAM_ARGUMENT_SUB, prefer_ffmpeg=False)
                idx_file = platform.make_temporary_file('.idx')
                sub_file = u'{}.sub'.format(os.path.splitext(idx_file)[0])
                result_commands.extend(
                    cmd.gen_bdsup2sub(track_file, idx_file,
                                      lang.alpha2(track.language())))
                track_sources[track.qualified_id()] = [idx_file, 0]
                mux_temporary_files.extend([idx_file, sub_file])
                if is_track_file_temporary:
                    result_commands.extend(
                        cmd.gen_del_files(args.sd, track_file))

        mux_path = platform.make_temporary_file('.mkv')

        # TODO add cover to files
        mux = ['call', 'mkvmerge']
        mux.extend(['--output', cmd.quote(mux_path)])
        mux.extend([
            '--no-track-tags', '--no-global-tags',
            '--disable-track-statistics-tags'
        ])

        track_ids_by_files = {}
        for qualified_id, (source_file,
                           source_file_track_id) in track_sources.iteritems():
            track_ids_by_files.setdefault(
                source_file, {})[qualified_id] = source_file_track_id
        if source_container_supported_by_mkvmerge:
            track_ids_by_files.setdefault(video_track.source_file(), {})

        # TODO tracks need to be extracted from 3gp and wmv containers before passing to mkvmerge
        source_file_ids = {}
        for i, (source_file,
                track_ids_map) in enumerate(track_ids_by_files.iteritems()):
            source_file_ids[source_file] = i
            for track_type, (tracks_flags_yes,
                             tracks_flag_no) in Track.TYPE_FLAGS.iteritems():
                cur_file_tracks = [
                    track for track in output_tracks[track_type]
                    if track.qualified_id() in track_ids_map
                ]
                if cur_file_tracks:
                    if tracks_flags_yes:
                        mux.append('{} {}'.format(
                            tracks_flags_yes, ','.join(
                                str(track_ids_map[track.qualified_id()])
                                for track in cur_file_tracks)))
                    for track in cur_file_tracks:
                        default = track.qualified_id(
                        ) == output_tracks[track_type][0].qualified_id()
                        file_track_id = track_ids_map[track.qualified_id()]
                        mux.append('--track-name {0}:""'.format(file_track_id))
                        if track_type == TrackType.SUB and track.encoding(
                        ) is not None:
                            mux.append('--sub-charset {0}:{1}'.format(
                                file_track_id, track.encoding()))
                        mux.append('--language {0}:{1}'.format(
                            file_track_id, track.language()))
                        mux.append('--default-track {0}:{1}'.format(
                            file_track_id, 'yes' if default else 'no'))
                        if track.is_forced():
                            mux.append(
                                '--forced-track {0}:yes'.format(file_track_id))
                elif tracks_flag_no:
                    mux.append(tracks_flag_no)
            file_flags = [
                '--no-track-tags', '--no-attachments', '--no-buttons',
                '--no-global-tags'
            ]
            if source_file != video_track.source_file():
                file_flags.append('--no-chapters')
            mux.append(u'{} {}'.format(u' '.join(file_flags),
                                       cmd.quote(source_file)))

        mux.append('--title ""')

        track_order = []
        for track_type in [TrackType.VID, TrackType.AUD, TrackType.SUB]:
            for track in output_tracks[track_type]:
                source_file, source_file_track_id = track_sources[
                    track.qualified_id()]
                track_order.append('{}:{}'.format(source_file_ids[source_file],
                                                  source_file_track_id))
        mux.append('--track-order {}'.format(','.join(track_order)))

        result_commands.append(u' '.join(mux))
        if len(mux_temporary_files) > 0:
            result_commands.extend(
                cmd.gen_del_files(args.sd, *sorted(set(mux_temporary_files))))

        # TODO mark mkv file with mkvexport version
        if movie.chapters_path() is not None:
            result_commands.append(u'mkvpropedit --chapters {} {}'.format(
                cmd.quote(movie.chapters_path()), cmd.quote(mux_path)))

        clean_mux_path = platform.make_temporary_file('.mkv')
        result_commands.append(u'call mkclean {} {}'.format(
            cmd.quote(mux_path), cmd.quote(clean_mux_path)))
        result_commands.extend(cmd.gen_del_files(args.sd, mux_path))
        result_commands.extend(
            cmd.gen_move_file(clean_mux_path, target_path, args.sd))

        if args.xx:
            result_commands.extend(
                cmd.gen_del_files(
                    args.sd,
                    *sorted(
                        set(media_file.path()
                            for media_file in movie.media_files()))))

        allowed_exit_codes = {'robocopy': 1, 'mkvmerge': 1}
        with codecs.open(MUX_BODY, 'a', 'utf-8') as body_file:
            for command in result_commands:
                fail_exit_code = 1
                for program, code in allowed_exit_codes.iteritems():
                    if program in command.lower():
                        fail_exit_code = code + 1
                stop_statement = u'call :stop {}'.format(
                    misc.random_printable(8))
                if fail_exit_code == 1:
                    prepared_commands = [
                        u'{} || {}'.format(command.strip(), stop_statement)
                    ]
                else:
                    prepared_commands = [
                        command.strip(),
                        u'if errorlevel {} {}'.format(fail_exit_code,
                                                      stop_statement)
                    ]
                for prep_command in prepared_commands:
                    body_file.write(u'{}\r\n'.format(prep_command))
            body_file.write(u'\r\n')

    return 0
Пример #13
0
 def fset(self, value):
     self._api_params['language'] = value
     self._api = tvdb.Tvdb(**self._api_params)
     self._language = value
Пример #14
0
    def __init__(self,
                 media,
                 tvdbid=None,
                 lang=None,
                 confidence=0.0,
                 query_thresh=1.0,
                 interactive=False,
                 grabber=None,
                 formatter=formatters.formatter_default,
                 interface=FileSystemInterface):
        """media : str or unicode
            Path to file, directory or glob pattern to media files.

        interactive : bool
            When true, tvdb_api interactive console is used to select from
            multiple results.

        grabber : tvdb_ui.BaseUI sublcass instance or None
            Grabs appropriate TVDB query result.
            If None, uses default grabber.
            Else, this option overrides `interactive`.

            If None, uses default QueryGrabber.

        formatter : scrappy.formatters.Formatter instance
            Object defining file name format to output.
            The default `Formatter` outputs file names in `seriesname.SXXEXX.episodename.ext` format.

        tvdbid : int or str
            TVDB ID number for the show being queried.

        lang : str or None
            Two-character language abbreviation (e.g.: 'en')

        confidence : float or int
            Minimum confidence index to consider a series-name inference as valid.

        query_thresh : float or int
            Maximum error to accept a result returned by TheTVDB.
            Default 1.0:  accept all TVDB results.
            NOTE:  ignored if not using default grabber.

        interface : AbstractMediaInterface class object
            Object inhereting from AbstractMediaInterface base class.
            The interface object provides a layer of abstraction for working with
            local files or abstract files (strings representing file names).
            By default, the FileSystemInterface class object is selected.
        """
        self.normalized_seriesname = None

        # TVDB api
        if not grabber and not interactive:
            grabber = partial(QueryGrabber, parent=self, thresh=query_thresh)

        self._api_params = {
            'language': lang,
            'search_all_languages': lang == None,
            'apikey': self._api_key,
            'interactive': interactive,
            'custom_ui': grabber
        }
        self._api = tvdb.Tvdb(
            **self._api_params
        )  # TODO:  render interactive and implement a custom UI

        # Other params
        self.id = tvdbid
        self.language = lang  # input validated in tvdb.Tvdb
        self.series = None
        if tvdbid:  # tolerate users who pass str
            if isinstance(tvdbid, str) or isinstance(tvdbid, unicode):
                tvdbid = int(tvdbid.strip())

        # Files
        self._files = interface(media)
        self.filemap = dict((fname, None) for fname in self._files)
        self.revert_filenames = self._files.revert
        self.formatter = formatter

        if not self.id:
            self._guess_series_name(confidence)
Пример #15
0
 def setup_class(cls):
     if cls.t is None:
         cls.t = tvdb_api.Tvdb(cache=True, banners=False)
Пример #16
0
    def __init__(self, datadir, configfile, daemon=False):

        # Verify if the log directory exists or create it
        logdir = os.path.join(datadir, 'logs')
        if not os.path.exists(logdir):
            os.mkdir(logdir)

        # Process log file name
        if daemon:
            if LOG_LEVEL is logging.DEBUG:
                logfile = os.path.join(logdir, "TraktForVLC-DEBUG.log")

                # Remove existing DEBUG file
                if os.path.isfile(logfile):
                    os.remove(logfile)
            else:
                logfile = os.path.join(
                    logdir,
                    "TraktForVLC-" + DATETIME.strftime("%Y%m%d-%H%M") + ".log")

            logging.basicConfig(
                format="%(asctime)s::%(name)s::%(levelname)s::%(message)s",
                level=LOG_LEVEL,
                filename=logfile)
        else:
            logging.basicConfig(
                format="%(asctime)s::%(name)s::%(levelname)s::%(message)s",
                level=LOG_LEVEL,
                stream=sys.stderr)

        self.log = logging.getLogger("TraktForVLC")

        e = 'e' if sys.platform.lower().startswith('win') else 'ë'
        self.log.info(
            "## TraktForVLC v" + __version__ + " " + __release_name__)
        self.log.info("## Copyright (C) 2014-2015  " +
                      "Rapha" + e + "l Beamonte <*****@*****.**>")
        self.log.info("##")
        self.log.info("## TraktForVLC is distributed in the hope that it " +
                      "will be useful, but")
        self.log.info("## with ABSOLUTELY NO WARRANTY. This is free " +
                      "software; you are welcome")
        self.log.info("## to redistribute and/or modify it under the terms " +
                      "of the GPL2.")
        self.log.info("")

        if not os.path.isfile(configfile):
            self.log.error("Config file " +
                           configfile +
                           " not found, exiting.")
            sys.exit(1)

        self.log.debug("Running on %s, with Python %s" % (
            platform.platform(), platform.python_version()))

        self.__check_version()

        # Load configuration
        self.configfile = configfile
        self.__load_config()

        for loglvl, logstr in AVAILABLE_LOGLVL:
            if LOG_LEVEL <= loglvl:
                loglevelstr = logstr
                break
        if loglevelstr is None:
            loglevelstr = str(LOG_LEVEL)

        self.log.info("Logger level is set to %s" % loglevelstr)
        self.log.info("-- Will scrobble movies ? %s" % (
            'Yes' if self.DO_SCROBBLE_MOVIE else 'No'))
        self.log.info("-- Will scrobble tv shows ? %s" % (
            'Yes' if self.DO_SCROBBLE_TV else 'No'))
        self.log.info("-- Will we mark movies as being watched ? %s" % (
            'Yes' if self.DO_WATCHING_MOVIE else 'No'))
        self.log.info("-- Will we mark tv shows as being watched ? %s" % (
            'Yes' if self.DO_WATCHING_TV else 'No'))
        self.log.info("-- Videos will be scrobbled after " +
                      str(self.SCROBBLE_PERCENT) +
                      "% of their duration has been exceeded")
        self.log.info("-- Timer set to " +
                      str(self.TIMER_INTERVAL) +
                      " secs")
        self.log.info("-- Video will be marked as \"is watching\" from " +
                      str(self.START_WATCHING_TIMER) +
                      " secs")

        # VLC configuration
        self.vlc_ip = self.config.get("VLC", "IP")
        self.vlc_port = self.config.getint("VLC", "Port")

        self.log.info("Listening VLC to " +
                      self.vlc_ip + ":" + str(self.vlc_port))

        # Trakt app configuration
        trakt_id = ("0e59f99095515c228d5fbc104e342574" +
                    "941aeeeda95946b8fa50b2b0366609bf")
        trakt_sc = ("3ed1d013ef80eb0bb45d8da8424b4b61" +
                    "3713abb057ed505683caf0baf1b5c650")

        # Trakt user information
        trakt = {
            "PIN":              None,
            "access_token":     None,
            "refresh_token":    None,
            "Username":         None,  # Now deprecated in Trakt v2 API
            "Password":         None,  # Now deprecated in Trakt v2 API
        }
        for opt in trakt.keys():
            if self.config.has_option("Trakt", opt):
                trakt[opt] = self.config.get("Trakt", opt)

        # Initialize Trakt client
        modifiedTime = time.strftime(
            '%Y-%m-%d',
            time.gmtime(os.path.getmtime(get_file())))
        self.trakt_client = TraktClient.TraktClient({
            'username':         trakt['Username'],
            'password':         trakt['Password'],
            'client_id':        trakt_id,
            'client_secret':    trakt_sc,
            'app_version':      __version__,
            'app_date':         modifiedTime,
            'pin':              trakt['PIN'],
            'access_token':     trakt['access_token'],
            'refresh_token':    trakt['refresh_token'],
            'callback_token':   self.__callback_token_change,
        })

        # Initialize TraktForVLC's cache
        self.resetCache()

        # Initialize tvdb api
        self.tvdb = tvdb_api.Tvdb(cache=False, language='en')

        self.watching_now = ""
        self.vlcTime = 0
        self.vlc_connected = True
Пример #17
0
    def __init__(self, datadir, configfile):

        # Verify if the log directory exists or create it
        logdir = os.path.join(datadir, 'logs')
        if not os.path.exists(logdir):
            os.mkdir(logdir)

        # Process log file name
        if LOG_LEVEL is logging.DEBUG:
            logfile = os.path.join(logdir, "TraktForVLC-DEBUG.log")

            # Remove existing DEBUG file
            if os.path.isfile(logfile):
                os.remove(logfile)
        else:
            logfile = os.path.join(
                logdir,
                "TraktForVLC-" + DATETIME.strftime("%Y%m%d-%H%M") + ".log")

        logging.basicConfig(
            format="%(asctime)s::%(name)s::%(levelname)s::%(message)s",
            level=LOG_LEVEL,
            filename=logfile,
            stream=sys.stdout)

        self.log = logging.getLogger("TraktForVLC")

        self.log.info("## TraktForVLC v" + __version__ + " " +
                      __release_name__)
        self.log.info("## Copyright (C) 2014-2015  " +
                      "Raphaël Beamonte <*****@*****.**>")
        self.log.info("##")
        self.log.info("## TraktForVLC is distributed in the hope that it " +
                      "will be useful, but")
        self.log.info("## with ABSOLUTELY NO WARRANTY. This is free " +
                      "software; you are welcome")
        self.log.info("## to redistribute and/or modify it under the terms " +
                      "of the GPL2.")
        self.log.info("")

        if not os.path.isfile(configfile):
            self.log.error("Config file " + configfile +
                           " not found, exiting.")
            exit()

        self.__check_version()

        self.config = ConfigParser.RawConfigParser()
        self.config.read(configfile)

        # Initialize timers
        if SMALL_TIMERS:
            self.TIMER_INTERVAL = 5
            self.START_WATCHING_TIMER = 5
        else:
            self.TIMER_INTERVAL = int(self.config.get("TraktForVLC", "Timer"))
            self.START_WATCHING_TIMER = int(
                self.config.get("TraktForVLC", "StartWatching"))

        # For the use of filenames instead of VLC window title
        self.USE_FILENAME = (True if self.config.get(
            "TraktForVLC", "UseFilenames") == 'Yes' else False)

        # Do we have to scrobble ?
        self.DO_SCROBBLE_MOVIE = (True if self.config.get(
            "TraktForVLC", "ScrobbleMovie") == 'Yes' else False)
        self.DO_SCROBBLE_TV = (True if self.config.get(
            "TraktForVLC", "ScrobbleTV") == 'Yes' else False)

        # Do we have to mark as watching ?
        self.DO_WATCHING_MOVIE = (True if self.config.get(
            "TraktForVLC", "WatchingMovie") == 'Yes' else False)
        self.DO_WATCHING_TV = (True if self.config.get(
            "TraktForVLC", "WatchingTV") == 'Yes' else False)

        # What percent should we use to scrobble videos ?
        self.SCROBBLE_PERCENT = int(
            self.config.get("TraktForVLC", "ScrobblePercent"))

        for loglvl, logstr in AVAILABLE_LOGLVL:
            if LOG_LEVEL <= loglvl:
                loglevelstr = logstr
                break
        if loglevelstr is None:
            loglevelstr = str(LOG_LEVEL)

        self.log.info("Logger level is set to %s" % loglevelstr)
        self.log.info("-- Will scrobble movies ? %s" %
                      ('Yes' if self.DO_SCROBBLE_MOVIE else 'No'))
        self.log.info("-- Will scrobble tv shows ? %s" %
                      ('Yes' if self.DO_SCROBBLE_TV else 'No'))
        self.log.info("-- Will we mark movies as being watched ? %s" %
                      ('Yes' if self.DO_WATCHING_MOVIE else 'No'))
        self.log.info("-- Will we mark tv shows as being watched ? %s" %
                      ('Yes' if self.DO_WATCHING_TV else 'No'))
        self.log.info("-- Videos will be scrobbled after " +
                      str(self.SCROBBLE_PERCENT) +
                      "% of their duration has been exceeded")
        self.log.info("-- Timer set to " + str(self.TIMER_INTERVAL) + " secs")
        self.log.info("-- Video will be marked as \"is watching\" from " +
                      str(self.START_WATCHING_TIMER) + " secs")

        # VLC configuration
        self.vlc_ip = self.config.get("VLC", "IP")
        self.vlc_port = self.config.getint("VLC", "Port")

        self.log.info("Listening VLC to " + self.vlc_ip + ":" +
                      str(self.vlc_port))

        # Trakt configuration
        trakt_api = ("0e59f99095515c228d5fbc104e342574" +
                     "941aeeeda95946b8fa50b2b0366609bf")
        trakt_username = self.config.get("Trakt", "Username")
        trakt_password = self.config.get("Trakt", "Password")

        self.log.info("Connect to Trakt(" + trakt_username + ", *********)")

        # Initialize Trakt client
        modifiedTime = time.strftime('%Y-%m-%d',
                                     time.gmtime(os.path.getmtime(__file__)))
        self.trakt_client = TraktClient.TraktClient(trakt_username,
                                                    trakt_password, trakt_api,
                                                    __version__, modifiedTime)

        self.resetCache()

        # Initialize tvdb api
        self.tvdb = tvdb_api.Tvdb(cache=False, language='en')

        self.watching_now = ""
        self.vlcTime = 0
        self.vlc_connected = True
Пример #18
0
def command_ep(bot, user, channel, args):
    """Usage: ep <series name>"""
    if not api_ok:
        return
    t = tvdb_api.Tvdb()
    now = datetime.now()
    # one day resolution maximum
    now = now.replace(hour=0, minute=0, second=0, microsecond=0)

    # prevent "Series '' not found"
    if not args:
        return

    try:
        series = t[args]
    except tvdb_exceptions.tvdb_shownotfound:
        bot.say(channel, "Series '%s' not found" % args)
        return

    future_episodes = []
    all_episodes = []

    # find all episodes with airdate > now
    for season_no, season in series.items():
        for episode_no, episode in season.items():
            firstaired = episode['firstaired']
            if not firstaired:
                continue
            airdate = datetime.strptime(firstaired, "%Y-%m-%d")
            td = airdate - now

            all_episodes.append(episode)
            # list all unaired episodes
            if td >= timedelta(0, 0, 0):
                future_episodes.append(episode)

    # if any future episodes were found, find out the one with airdate closest to now
    if future_episodes:
        # sort the list just in case it's out of order (specials are season 0)
        future_episodes = sorted(future_episodes, key=itemgetter('firstaired'))
        episode = future_episodes[0]
        td = datetime.strptime(episode['firstaired'], "%Y-%m-%d") - now

        if td.days == 1:
            airdate = "tomorrow"
        elif td.days > 1:
            airdate = "%s (%d days)" % (episode['firstaired'], td.days)
        else:
            airdate = "today"

        season_ep = "%dx%02d" % (int(float(episode['combined_season'])),
                                 int(float(episode['combined_episodenumber'])))
        msg = "Next episode of %s %s '%s' airs %s" % (
            series.data['seriesname'], season_ep, episode['episodename'],
            airdate)
    # no future episodes found, show the latest one
    elif all_episodes:
        # find latest episode of the show
        all_episodes = sorted(all_episodes, key=itemgetter('firstaired'))
        episode = all_episodes[-1]

        ## episode age in years and days
        td = now - datetime.strptime(episode['firstaired'], "%Y-%m-%d")
        years, days = td.days // 365, td.days % 365
        agestr = []
        if years >= 1:
            agestr.append("%d years" % years)
        if days > 0:
            agestr.append("%d days" % days)

        airdate = "%s (%s ago)" % (episode['firstaired'], " ".join(agestr))

        season_no = int(episode['combined_season'])
        # the episode number is sometimes returned as a float, hack it.
        episode_no = int(float(episode['combined_episodenumber']))

        season_ep = "%dx%02d" % (season_no, episode_no)
        msg = "Latest episode of %s %s '%s' aired %s" % (
            series.data['seriesname'], season_ep, episode['episodename'],
            airdate)
    else:
        msg = "No new or past episode airdates found for %s" % series.data[
            'seriesname']

    bot.say(channel, msg.encode("UTF-8"))
Пример #19
0
from django.db import models
from django.core.urlresolvers import reverse
import threading
import time

import tvdb_api
_t = tvdb_api.Tvdb(cache=False)


def _active_sleep(interval):
    # Sleep, but occasionally wake to check the system time.
    # Takes into account time when the system is off.
    sleep_time = min(60, interval / 10)
    start = time.time()
    while time.time() - start < interval:
        time.sleep(sleep_time)


class ShowManager(models.Manager):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._update_thread_started = False

    def from_tvdb(self, id_, populate=True):
        # Load a show from the tvdb using a TVDB id.
        try:
            # get show if it already exists
            show = Show.objects.get(pk=id_)

            # populate show if necessary
            if show.populated or not populate:
Пример #20
0
 def __init__(self):
     # todo: selectfirst=False
     self.tvdb = tvdb_api.Tvdb(banners=True, actors=True)
Пример #21
0
        path = sys.argv[1]
    for fn in os.listdir(path):
        if os.path.isfile(path + fn):
            # Split out file extension
            bn, ext = os.path.splitext(fn)
            if bn in matches:
                nbn = matches[bn]
            else:
                nbn = search_episode_by_filename(bn)
                matches[bn] = nbn
            print("{} -> {}".format(bn, nbn))
            os.rename(path + fn, path + nbn + ext)


if __name__ == "__main__":
    t = tvdb_api.Tvdb(language='de')
    show = t[TVDB_TATORT_SHOW_ID]

    # Build a dict of all show titles, indexed by the TVDB episode ID
    # Note: we need to use dicts here and not lists, as fuzzywuzzy only returns
    # the matching ID when using a dict, not a list.
    tatort_episodes = {}
    tatort_titles = {}
    for cur_season in show.values():
        for cur_episode in cur_season.values():
            episode_id = cur_episode['id']

            # Prepare the title string used for matching the filename
            # We filter the title as we get it from TVDB to contain only the
            # title. Example:
            # "Episode 2016x39 - Janneke & Brix - 05 - Land in dieser Zeit"
Пример #22
0
def tvdb_fetch(series, season, episode):
    t = tvdb_api.Tvdb()
    episode = t[series][season][episode]
    return episode
Пример #23
0
 def setUp(self):
     if self.t is None:
         self.__class__.t = tvdb_api.Tvdb(cache=True, actors=True)
Пример #24
0
def tvnamer(paths):
    # type: (List[str]) -> None
    """Main tvnamer function, takes an array of paths, does stuff.
    """

    print("#" * 20)
    print("# Starting tvnamer")

    episodes_found = []

    for cfile in find_files(paths):
        parser = FileParser(cfile)
        try:
            episode = parser.parse()
        except InvalidFilename as e:
            warn("Invalid filename: %s" % e)
        else:
            if (episode.seriesname is None and Config["force_name"] is None
                    and Config["series_id"] is None):
                warn(
                    "Parsed filename did not contain series name (and --name or --series-id not specified), skipping: %s"
                    % cfile)

            else:
                episodes_found.append(episode)

    if len(episodes_found) == 0:
        raise NoValidFilesFoundError()

    print("# Found %d episode" % len(episodes_found) +
          ("s" * (len(episodes_found) > 1)))

    # Sort episodes by series name, season and episode number
    episodes_found.sort(key=lambda x: x.sortable_info())

    # episode sort order
    if Config["order"] == "dvd":
        dvdorder = True
    else:
        dvdorder = False

    if Config["tvdb_api_key"] is not None:
        LOG.debug("Using custom API key from config")
        api_key = Config["tvdb_api_key"]
    else:
        LOG.debug("Using tvnamer default API key")
        api_key = TVNAMER_API_KEY

    if os.getenv("TVNAMER_TEST_MODE", "0") == "1":
        from .test_cache import get_test_cache_session
        cache = get_test_cache_session()
    else:
        cache = True

    tvdb_instance = tvdb_api.Tvdb(
        interactive=not Config["select_first"],
        search_all_languages=Config["search_all_languages"],
        language=Config["language"],
        dvdorder=dvdorder,
        cache=cache,
        apikey=api_key,
    )

    for episode in episodes_found:
        process_file(tvdb_instance, episode)
        print("")

    print("#" * 20)
    print("# Done")
Пример #25
0
        """Test Tvdb.search method
        """
        results = self.t.search("my name is earl")
        all_ids = [x['id'] for x in results]
        assert 75397 in all_ids


class TestTvdbAltNames:
    t = None

    @classmethod
    def setup_class(cls):
        if cls.t is None:
            cls.t = tvdb_api.Tvdb(cache=get_test_cache_session(), actors=True)

    def test_1(self):
        """Tests basic access of series name alias
        """
        results = self.t.search("Don't Trust the B---- in Apartment 23")
        series = results[0]
        assert 'Apartment 23' in series['aliases']


if __name__ == '__main__':
    cache = get_test_cache_session()
    t = tvdb_api.Tvdb(cache=cache)
    t['scrubs'][1][2]
    t = tvdb_api.Tvdb(cache=cache)
    t['scrubs'][1][2]
    # pytest.main()
Пример #26
0
    def setup_class(cls):
        if cls.t_dvd is None:
            cls.t_dvd = tvdb_api.Tvdb(cache=True, dvdorder=True)

        if cls.t_air is None:
            cls.t_air = tvdb_api.Tvdb(cache=True)
Пример #27
0
 def test_episode_name_french(self):
     """Check episode data is in French (language="fr")
     """
     t = tvdb_api.Tvdb(cache=get_test_cache_session(), language="fr")
     assert t['scrubs'][1][1]['episodeName'] == "Mon premier jour"
     assert t['scrubs']['overview'].startswith(u"J.D. est un jeune m\xe9decin qui d\xe9bute")
Пример #28
0
 def setup_class(cls):
     if cls.t is None:
         cls.t = tvdb_api.Tvdb(cache=True, actors=True)
Пример #29
0
 def setup_class(cls):
     if cls.t is None:
         cls.t = tvdb_api.Tvdb(cache=get_test_cache_session(), actors=True)
Пример #30
0
class SmartUI(tvdb_api.BaseUI):
    """Returns the latest series that is actually airing"""
    def selectSeries(self, allSeries):
        t = tvdb_api.Tvdb()
        # reverse order, latest shows first(?)
        for series in reversed(allSeries):
            # search with ID directly to skip name->ID lookup in library
            status = t[series['id']].data['status']
            if status == "Continuing":
                return series
        if len(allSeries) > 0:
            return allSeries[0]


if __name__ == "__main__":
    api = tvdb_api.Tvdb(custom_ui=SmartUI)
    print(api['doctor who'])  # Doctor Who 2005
    print(api['castle'])  # Castle 2009
    print(api['house of cards'])  # House of Cards (US)


def command_ep(bot, user, channel, args):
    """Usage: ep <series name>"""
    if not api_ok:
        return
    t = tvdb_api.Tvdb(custom_ui=SmartUI)
    now = datetime.now()
    # one day resolution maximum
    now = now.replace(hour=0, minute=0, second=0, microsecond=0)

    # prevent "Series '' not found"