This file is indexed.

/usr/lib/python3/dist-packages/subliminal/api.py is in python3-subliminal 0.7.4-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import collections
import io
import logging
import operator
import babelfish
import pkg_resources
from .exceptions import ProviderNotAvailable, InvalidSubtitle
from .subtitle import get_subtitle_path


logger = logging.getLogger(__name__)

#: Entry point for the providers
PROVIDERS_ENTRY_POINT = 'subliminal.providers'


def list_subtitles(videos, languages, providers=None, provider_configs=None):
    """List subtitles for `videos` with the given `languages` using the specified `providers`

    :param videos: videos to list subtitles for
    :type videos: set of :class:`~subliminal.video.Video`
    :param languages: languages of subtitles to search for
    :type languages: set of :class:`babelfish.Language`
    :param providers: providers to use for the search, if not all
    :type providers: list of string or None
    :param provider_configs: configuration for providers
    :type provider_configs: dict of provider name => provider constructor kwargs
    :return: found subtitles
    :rtype: dict of :class:`~subliminal.video.Video` => [:class:`~subliminal.subtitle.Subtitle`]

    """
    provider_configs = provider_configs or {}
    subtitles = collections.defaultdict(list)
    # filter videos
    videos = [v for v in videos if v.subtitle_languages & languages < languages]
    if not videos:
        logger.info('No video to download subtitles for with languages %r', languages)
        return subtitles
    subtitle_languages = set.intersection(*[v.subtitle_languages for v in videos])
    for provider_entry_point in pkg_resources.iter_entry_points(PROVIDERS_ENTRY_POINT):
        # filter and initialize provider
        if providers is not None and provider_entry_point.name not in providers:
            logger.debug('Skipping provider %r: not in the list', provider_entry_point.name)
            continue
        Provider = provider_entry_point.load()
        provider_languages = Provider.languages & languages - subtitle_languages
        if not provider_languages:
            logger.info('Skipping provider %r: no language to search for', provider_entry_point.name)
            continue
        provider_videos = [v for v in videos if Provider.check(v)]
        if not provider_videos:
            logger.info('Skipping provider %r: no video to search for', provider_entry_point.name)
            continue

        # list subtitles with the provider
        try:
            with Provider(**provider_configs.get(provider_entry_point.name, {})) as provider:
                for provider_video in provider_videos:
                    provider_video_languages = provider_languages - provider_video.subtitle_languages
                    if not provider_video_languages:
                        logger.debug('Skipping provider %r: no language to search for for video %r',
                                     provider_entry_point.name, provider_video)
                        continue
                    logger.info('Listing subtitles with provider %r for video %r with languages %r',
                                provider_entry_point.name, provider_video, provider_video_languages)
                    try:
                        provider_subtitles = provider.list_subtitles(provider_video, provider_video_languages)
                    except ProviderNotAvailable:
                        logger.warning('Provider %r is not available, discarding it', provider_entry_point.name)
                        break
                    except:
                        logger.exception('Unexpected error in provider %r', provider_entry_point.name)
                        continue
                    logger.info('Found %d subtitles', len(provider_subtitles))
                    subtitles[provider_video].extend(provider_subtitles)
        except ProviderNotAvailable:
            logger.warning('Provider %r is not available, discarding it', provider_entry_point.name)
    return subtitles


def download_subtitles(subtitles, provider_configs=None, single=False):
    """Download subtitles

    :param subtitles: subtitles to download
    :type subtitles: dict of :class:`~subliminal.video.Video` => [:class:`~subliminal.subtitle.Subtitle`]
    :param provider_configs: configuration for providers
    :type provider_configs: dict of provider name => provider constructor kwargs
    :param bool single: download with .srt extension if `True`, add language identifier otherwise

    """
    provider_configs = provider_configs or {}
    discarded_providers = set()
    providers_by_name = {ep.name: ep.load() for ep in pkg_resources.iter_entry_points(PROVIDERS_ENTRY_POINT)}
    initialized_providers = {}
    try:
        for video, video_subtitles in subtitles.items():
            languages = {subtitle.language for subtitle in video_subtitles}
            downloaded_languages = set()
            for subtitle in video_subtitles:
                # filter
                if subtitle.language in downloaded_languages:
                    continue
                if subtitle.provider_name in discarded_providers:
                    logger.debug('Skipping subtitle from discarded provider %r', subtitle.provider_name)
                    continue

                # initialize provider
                if subtitle.provider_name in initialized_providers:
                    provider = initialized_providers[subtitle.provider_name]
                else:
                    provider = providers_by_name[subtitle.provider_name](**provider_configs.get(subtitle.provider_name, {}))
                    try:
                        provider.initialize()
                    except ProviderNotAvailable:
                        logger.warning('Provider %r is not available, discarding it', subtitle.provider_name)
                        discarded_providers.add(subtitle.provider_name)
                        continue
                    initialized_providers[subtitle.provider_name] = provider

                # download subtitles
                subtitle_path = get_subtitle_path(video.name, None if single else subtitle.language)
                logger.info('Downloading subtitle %r into %r', subtitle, subtitle_path)
                try:
                    subtitle_text = provider.download_subtitle(subtitle)
                except ProviderNotAvailable:
                    logger.warning('Provider %r is not available, discarding it', subtitle.provider_name)
                    discarded_providers.add(subtitle.provider_name)
                    continue
                except InvalidSubtitle:
                    logger.info('Invalid subtitle, skipping it')
                    continue
                except:
                    logger.exception('Unexpected error in provider %r', subtitle.provider_name)
                    continue
                with io.open(subtitle_path, 'w', encoding='utf-8') as f:
                    f.write(subtitle_text)
                downloaded_languages.add(subtitle.language)
                if single or downloaded_languages == languages:
                    break
    finally:  # terminate providers
        for (provider_name, provider) in initialized_providers.items():
            try:
                provider.terminate()
            except ProviderNotAvailable:
                logger.warning('Provider %r is not available, unable to terminate', provider_name)
            except:
                logger.exception('Unexpected error in provider %r', provider_name)


def download_best_subtitles(videos, languages, providers=None, provider_configs=None, single=False, min_score=0,
                            hearing_impaired=False):
    """Download the best subtitles for `videos` with the given `languages` using the specified `providers`

    :param videos: videos to download subtitles for
    :type videos: set of :class:`~subliminal.video.Video`
    :param languages: languages of subtitles to download
    :type languages: set of :class:`babelfish.Language`
    :param providers: providers to use for the search, if not all
    :type providers: list of string or None
    :param provider_configs: configuration for providers
    :type provider_configs: dict of provider name => provider constructor kwargs
    :param bool single: download with .srt extension if `True`, add language identifier otherwise
    :param int min_score: minimum score for subtitles to download
    :param bool hearing_impaired: download hearing impaired subtitles

    """
    provider_configs = provider_configs or {}
    discarded_providers = set()
    downloaded_subtitles = collections.defaultdict(list)
    # filter videos
    videos = [v for v in videos if v.subtitle_languages & languages < languages
              and (not single or babelfish.Language('und') not in v.subtitle_languages)]
    if not videos:
        logger.info('No video to download subtitles for with languages %r', languages)
        return downloaded_subtitles
    # filter and initialize providers
    subtitle_languages = set.intersection(*[v.subtitle_languages for v in videos])
    initialized_providers = {}
    for provider_entry_point in pkg_resources.iter_entry_points(PROVIDERS_ENTRY_POINT):
        if providers is not None and provider_entry_point.name not in providers:
            logger.debug('Skipping provider %r: not in the list', provider_entry_point.name)
            continue
        Provider = provider_entry_point.load()
        if not Provider.languages & languages - subtitle_languages:
            logger.info('Skipping provider %r: no language to search for', provider_entry_point.name)
            continue
        if not [v for v in videos if Provider.check(v)]:
            logger.info('Skipping provider %r: no video to search for', provider_entry_point.name)
            continue
        provider = Provider(**provider_configs.get(provider_entry_point.name, {}))
        try:
            provider.initialize()
        except ProviderNotAvailable:
            logger.warning('Provider %r is not available, discarding it', provider_entry_point.name)
            continue
        initialized_providers[provider_entry_point.name] = provider
    try:
        for video in videos:
            # search for subtitles
            subtitles = []
            for provider_name, provider in initialized_providers.items():
                if provider.check(video):
                    if provider_name in discarded_providers:
                        logger.debug('Skipping discarded provider %r', provider_name)
                        continue
                    provider_video_languages = provider.languages & languages - video.subtitle_languages
                    if not provider_video_languages:
                        logger.debug('Skipping provider %r: no language to search for for video %r', provider_name,
                                     video)
                        continue
                    logger.info('Listing subtitles with provider %r for video %r with languages %r',
                                provider_name, video, provider_video_languages)
                    try:
                        provider_subtitles = provider.list_subtitles(video, provider_video_languages)
                    except ProviderNotAvailable:
                        logger.warning('Provider %r is not available, discarding it', provider_name)
                        discarded_providers.add(provider_name)
                        continue
                    except:
                        logger.exception('Unexpected error in provider %r', provider_name)
                        continue
                    logger.info('Found %d subtitles', len(provider_subtitles))
                    subtitles.extend(provider_subtitles)

            # find the best subtitles and download them
            downloaded_languages = video.subtitle_languages.copy()
            for subtitle, score in sorted([(s, s.compute_score(video)) for s in subtitles],
                                          key=operator.itemgetter(1), reverse=True):
                # filter
                if subtitle.provider_name in discarded_providers:
                    logger.debug('Skipping subtitle from discarded provider %r', subtitle.provider_name)
                    continue
                if subtitle.hearing_impaired != hearing_impaired:
                    logger.debug('Skipping subtitle: hearing impaired != %r', hearing_impaired)
                    continue
                if score < min_score:
                    logger.debug('Skipping subtitle: score < %d', min_score)
                    continue
                if subtitle.language in downloaded_languages:
                    logger.debug('Skipping subtitle: %r already downloaded', subtitle.language)
                    continue

                # download
                provider = initialized_providers[subtitle.provider_name]
                subtitle_path = get_subtitle_path(video.name, None if single else subtitle.language)
                logger.info('Downloading subtitle %r with score %d into %r', subtitle, score, subtitle_path)
                try:
                    subtitle_text = provider.download_subtitle(subtitle)
                    downloaded_subtitles[video].append(subtitle)
                except ProviderNotAvailable:
                    logger.warning('Provider %r is not available, discarding it', subtitle.provider_name)
                    discarded_providers.add(subtitle.provider_name)
                    continue
                except InvalidSubtitle:
                    logger.info('Invalid subtitle, skipping it')
                    continue
                except:
                    logger.exception('Unexpected error in provider %r', subtitle.provider_name)
                    continue
                with io.open(subtitle_path, 'w', encoding='utf-8') as f:
                    f.write(subtitle_text)
                downloaded_languages.add(subtitle.language)
                if single or downloaded_languages >= languages:
                    logger.debug('All languages downloaded')
                    break
    finally:  # terminate providers
        for (provider_name, provider) in initialized_providers.items():
            try:
                provider.terminate()
            except ProviderNotAvailable:
                logger.warning('Provider %r is not available, unable to terminate', provider_name)
            except:
                logger.exception('Unexpected error in provider %r', provider_name)
    return downloaded_subtitles