Esempio n. 1
0
def subscribe():
    form = SubscribeForm()
    if form.validate_on_submit():
        videos = get_channel_videos(form.channel.data)

        if not videos:
            raise DownloadError('Channel \'{}\' not found'.format(
                form.channel.data))

        channel = Channel(name=videos[0]['uploader_id'],
                          channel_id=videos[0]['channel_id'])
        db.session.add(channel)
        db.session.commit()

        for v in videos:
            if v and 'id' in v:
                video = Video(video_id=v['id'],
                              title=v['title'],
                              channel_id=channel.id,
                              description=v['description'],
                              thumbnail_url=v['thumbnail'],
                              duration=v['duration'],
                              upload_date=datetime.strptime(
                                  v['upload_date'], '%Y%m%d'),
                              view_count=v['view_count'])
                db.session.add(video)
        db.session.commit()

    return redirect('/channels')
Esempio n. 2
0
    def _extract_songs(self, ydl: youtube_dl.YoutubeDL, url: str):
        info = ydl.extract_info(url, download=False)
        if not info:
            raise DownloadError('Data could not be retrieved')

        if '_type' in info and info['_type'] == 'playlist':
            entries = info['entries']
        else:
            entries = [info]

        results = [(e['title'], e['url']) for e in entries]
        return results
Esempio n. 3
0
def get_meta_info(url):
    """
    Get metadata info from YouTube video.

    :param url: YouTube video URL
    """
    opts = {
        'format': 'bestaudio/best',
        'forcefilename': True,
        'noplaylist': True
    }
    # Try up to 3 times, as youtubedl tends to be flakey
    for _ in range(settings.YOUTUBE_MAX_RETRIES):
        try:
            with YoutubeDL(opts) as ydl:
                info = ydl.extract_info(url, download=False)
                filename = ydl.prepare_filename(info)

                parsed_artist = ''
                parsed_title = ''

                # Use youtube_title_parse library to attempt to parse the YouTube video title into
                # the track's artist and title.
                result = get_artist_title(info['title'])
                if result:
                    parsed_artist, parsed_title = result

                metadata = {
                    # YT video title
                    'title': info['title'],
                    # YT video uploader
                    'uploader': info['uploader'],
                    # YT video's embedded track artist (some official songs)
                    'embedded_artist': info['artist'],
                    # YT video's embedded track title (some official songs)
                    'embedded_title': info['track'],
                    # Artist name parsed from the YouTube video title
                    'parsed_artist': parsed_artist,
                    # Title parsed from the YouTube video title
                    'parsed_title': parsed_title,
                    # Duration of YouTube video in seconds
                    'duration': info['duration'],
                    # YouTube video URL
                    'url': info['webpage_url'],
                    # Filename (including extension)
                    'filename': filename
                }
                return metadata
        except DownloadError:
            # Allow for retry
            pass
    raise DownloadError('Unable to parse YouTube link')
Esempio n. 4
0
def serve_mp3_file(videoid):
    def set_downloaded_flag(videoid):
        video = Video.query.filter_by(video_id=videoid).first_or_404()
        video.is_downloaded = True
        db.session.commit()
        return

    try:
        if download_mp3(videoid) == 0:
            set_downloaded_flag(videoid)
            return send_file('static/{}.mp3'.format(videoid),
                             attachment_filename='{}.mp3'.format(videoid))
    except:
        raise DownloadError(
            'Could not download audio for video ID \'{}\''.format(videoid))
    finally:
        try:
            os.remove('app/static/{}.mp3'.format(videoid))
            print('Deleted file \'{}.mp3\''.format(videoid))
        except OSError:
            raise DownloadError(
                'Could not download audio for video ID \'{}\''.format(videoid))
Esempio n. 5
0
def unsubscribe():
    form = UnsubscribeForm()
    #    if form.validate_on_submit():
    channel = Channel.query.get(form.channel.data)
    if not channel:
        raise DownloadError('Channel \'{}\' not found'.format(
            form.channel.data))

    for video in Video.query.with_parent(channel).all():
        db.session.delete(video)

    db.session.delete(channel)
    db.session.commit()

    return redirect('/channels')
Esempio n. 6
0
    def test_download_episode__downloading_failed__roll_back_changes__ok(
            self, episode, mocked_youtube, mocked_ffmpeg, mocked_s3,
            mocked_generate_rss_task, dbs):
        file_path = settings.TMP_AUDIO_PATH / episode.file_name
        with open(file_path, "wb") as file:
            file.write(b"EpisodeData")

        mocked_youtube.download.side_effect = DownloadError(
            "Video is not available")

        result = await_(DownloadEpisodeTask(db_session=dbs).run(episode.id))

        episode = await_(Episode.async_get(dbs, id=episode.id))
        mocked_youtube.download.assert_called_with([episode.watch_url])
        mocked_s3.upload_file.assert_not_called()
        mocked_generate_rss_task.run.assert_not_called()

        assert result == FinishCode.ERROR
        assert episode.status == Episode.Status.ERROR
        assert episode.published_at is None
Esempio n. 7
0
def play_url():  # this only plays http urls for now, torrents soon.
    global title
    url = request.args.get('url')  # grab url from /play?url=*

    if not url.startswith('http'):  # in case the user forgot it
        log('url missing http/wrong protocol')
        url = 'http://' + url  # let's assume it's http, not https

    log('received url %s' % url)
    log('requesting headers from %s...' % url)
    req = Request(url)
    req.get_method = lambda: 'HEAD'  # only request headers, no content
    response = urlopen(req)
    ctype = response.headers['content-type']
    ctype_split = ctype.split('/')  # split into 2 parts
    log('headers received. content type is %s' % ctype)

    try:
        if ctype_split[0] == 'audio' or ctype_split[0] == 'video':
            log('url was raw media file, playing! :)')
            title = url  # i guess this works? :T
            play_omxplayer(url)
        elif ctype_split[1] == 'x-bittorrent':
            log('loading torrents not implemented.')
            # this isn't implemented yet.
        elif ctype_split[0] == 'text':
            # here we check if it's a livestream, and if so get the RTMP url
            log('checking if url is a livestream...')
            live = Livestreamer()
            try:
                if "youtube" in url:
                    raise RuntimeError(
                        "youtube is f****d up w/ streaming, falling back to youtube-dl"
                    )
                plugin = live.resolve_url(url)
                streams = plugin.get_streams()
                stream = streams.get(
                    "best")  # fingers crossed for best quality

                stream_url_types = ['rtmp', 'url'
                                    ]  # things that livestreamer can have :D
                for stream_type in stream_url_types:
                    if hasattr(stream, stream_type):
                        log('url is livestream!')
                        title = "%s (livestream)" % url
                        play_omxplayer(getattr(stream, stream_type))
                        return '', 204
            except (PluginError, RuntimeError
                    ) as e:  # therefore url is not (supported) livestream
                pass  # continue and let youtube-dl try.

            log('loading youtube-dl for further processing')
            ydl = YoutubeDL({
                'outtmpl': '%(id)s%(ext)s',
                'restrictfilenames': True
            })
            ydl.add_default_info_extractors()
            result = ydl.extract_info(url, download=False)
            if 'entries' in result:  # if video is a playlist
                video = result['entries'][
                    0]  # play the 1st video in the playlist
            else:
                video = result
            play_omxplayer(video['url'])
            title = video['title']
        else:
            raise DownloadError('Invalid filetype: not audio, video, or text.')

        return '', 204  # success w/ no response!
    except (UnicodeDecodeError, DownloadError) as e:
        return _ANSI_ESCAPE_REXP.sub('', str(e)), 400  # send error message