Skip to content

Commit

Permalink
Call the real YouTube transcript API
Browse files Browse the repository at this point in the history
Call the real YouTube transcript API to get video transcripts, instead
of always returning a hard-coded transcript.
  • Loading branch information
seanh committed Jun 27, 2023
1 parent 6814d33 commit 5353b40
Show file tree
Hide file tree
Showing 10 changed files with 102 additions and 1,322 deletions.
3 changes: 3 additions & 0 deletions requirements/dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ requests==2.31.0
# -r requirements/prod.txt
# checkmatelib
# requests-oauthlib
# youtube-transcript-api
requests-oauthlib==1.3.0
# via
# -r requirements/prod.txt
Expand Down Expand Up @@ -275,6 +276,8 @@ wired==0.3
# via
# -r requirements/prod.txt
# pyramid-services
youtube-transcript-api==0.6.1
# via -r requirements/prod.txt
zipp==3.4.1
# via
# -r requirements/prod.txt
Expand Down
3 changes: 3 additions & 0 deletions requirements/functests.txt
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ requests==2.31.0
# -r requirements/prod.txt
# checkmatelib
# requests-oauthlib
# youtube-transcript-api
requests-oauthlib==1.3.0
# via
# -r requirements/prod.txt
Expand Down Expand Up @@ -255,6 +256,8 @@ wired==0.3
# via
# -r requirements/prod.txt
# pyramid-services
youtube-transcript-api==0.6.1
# via -r requirements/prod.txt
zipp==3.4.1
# via
# -r requirements/prod.txt
Expand Down
5 changes: 5 additions & 0 deletions requirements/lint.txt
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,7 @@ requests==2.31.0
# -r requirements/tests.txt
# checkmatelib
# requests-oauthlib
# youtube-transcript-api
requests-oauthlib==1.3.0
# via
# -r requirements/functests.txt
Expand Down Expand Up @@ -407,6 +408,10 @@ wired==0.3
# pyramid-services
wrapt==1.12.1
# via astroid
youtube-transcript-api==0.6.1
# via
# -r requirements/functests.txt
# -r requirements/tests.txt
zipp==3.4.1
# via
# -r requirements/functests.txt
Expand Down
1 change: 1 addition & 0 deletions requirements/prod.in
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ whitenoise
google-auth-oauthlib
marshmallow
webargs
youtube-transcript-api
3 changes: 3 additions & 0 deletions requirements/prod.txt
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ requests==2.31.0
# -r requirements/prod.in
# checkmatelib
# requests-oauthlib
# youtube-transcript-api
requests-oauthlib==1.3.0
# via google-auth-oauthlib
rsa==4.7.2
Expand Down Expand Up @@ -144,6 +145,8 @@ whitenoise==6.4.0
# via -r requirements/prod.in
wired==0.3
# via pyramid-services
youtube-transcript-api==0.6.1
# via -r requirements/prod.in
zipp==3.4.1
# via
# importlib-metadata
Expand Down
3 changes: 3 additions & 0 deletions requirements/tests.txt
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ requests==2.31.0
# -r requirements/prod.txt
# checkmatelib
# requests-oauthlib
# youtube-transcript-api
requests-oauthlib==1.3.0
# via
# -r requirements/prod.txt
Expand Down Expand Up @@ -253,6 +254,8 @@ wired==0.3
# via
# -r requirements/prod.txt
# pyramid-services
youtube-transcript-api==0.6.1
# via -r requirements/prod.txt
zipp==3.4.1
# via
# -r requirements/prod.txt
Expand Down
11 changes: 11 additions & 0 deletions tests/unit/via/services/youtube_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ def test_enabled(self, enabled):
def test_get_video_id(self, url, expected_video_id, svc):
assert expected_video_id == svc.get_video_id(url)

def test_get_transcript(self, YouTubeTranscriptApi, svc):
transcript = svc.get_transcript(sentinel.video_id)

YouTubeTranscriptApi.get_transcript.assert_called_once_with(sentinel.video_id)
assert transcript == YouTubeTranscriptApi.get_transcript.return_value

@pytest.fixture
def svc(self):
return YouTubeService(enabled=True)
Expand All @@ -56,3 +62,8 @@ def YouTubeService(self, patch):
@pytest.fixture
def youtube_service(self, YouTubeService):
return YouTubeService.return_value


@pytest.fixture(autouse=True)
def YouTubeTranscriptApi(patch):
return patch("via.services.youtube.YouTubeTranscriptApi")
46 changes: 36 additions & 10 deletions tests/unit/via/views/api/youtube_test.py
Original file line number Diff line number Diff line change
@@ -1,29 +1,55 @@
import logging
from unittest.mock import sentinel

import pytest
from h_matchers import Any
from pyramid.httpexceptions import HTTPNotFound

from via.views.api import youtube


class TestTranscript:
def test_it(self, pyramid_request):
def test_it(self, pyramid_request, youtube_service):
response = youtube.transcript(pyramid_request)

youtube_service.get_transcript.assert_called_once_with(sentinel.video_id)
assert response == {
"data": {
"type": "transcripts",
"id": "1",
"attributes": {"segments": Any.list()},
"id": sentinel.video_id,
"attributes": {"segments": youtube_service.get_transcript.return_value},
}
}

def test_it_errors_if_the_video_id_is_unknown(self, pyramid_request):
pyramid_request.matchdict["video_id"] = "unknown"
def test_it_handles_errors_from_youtube(
self, caplog, pyramid_request, youtube_service, report_exception_to_sentry
):
exception = youtube_service.get_transcript.side_effect = RuntimeError(
"Test error"
)

with pytest.raises(HTTPNotFound):
youtube.transcript(pyramid_request)
response = youtube.transcript(pyramid_request)

report_exception_to_sentry.assert_called_once_with(exception)
assert caplog.record_tuples == [
("via.views.api.youtube", logging.ERROR, str(exception))
]
assert pyramid_request.response.status_int == 500
assert response == {
"errors": [
{
"status": 500,
"code": "failed_to_get_transcript",
"title": "Failed to get transcript from YouTube",
"detail": str(exception),
}
]
}

@pytest.fixture
def pyramid_request(self, pyramid_request):
pyramid_request.matchdict["video_id"] = "1"
pyramid_request.matchdict["video_id"] = sentinel.video_id
return pyramid_request


@pytest.fixture(autouse=True)
def report_exception_to_sentry(patch):
return patch("via.views.api.youtube.report_exception_to_sentry")
11 changes: 11 additions & 0 deletions via/services/youtube.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from urllib.parse import parse_qs, urlparse

from youtube_transcript_api import YouTubeTranscriptApi


class YouTubeService:
def __init__(self, enabled: bool):
Expand Down Expand Up @@ -39,6 +41,15 @@ def get_video_id(self, url):

return None

def get_transcript(self, video_id):
"""
Call the YouTube API and return the transcript for the given video_id.
:raise Exception: this method might raise any type of exception that
YouTubeTranscriptApi raises
"""
return YouTubeTranscriptApi.get_transcript(video_id)


def factory(_context, request):
return YouTubeService(enabled=request.registry.settings["youtube_transcripts"])
Loading

0 comments on commit 5353b40

Please sign in to comment.