youtube-rb 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +703 -0
- data/Rakefile +6 -0
- data/bin/console +10 -0
- data/bin/setup +8 -0
- data/lib/youtube-rb/client.rb +160 -0
- data/lib/youtube-rb/downloader.rb +632 -0
- data/lib/youtube-rb/extractor.rb +425 -0
- data/lib/youtube-rb/options.rb +186 -0
- data/lib/youtube-rb/version.rb +3 -0
- data/lib/youtube-rb/video_info.rb +179 -0
- data/lib/youtube-rb/ytdlp_wrapper.rb +269 -0
- data/lib/youtube-rb.rb +69 -0
- data/spec/client_spec.rb +514 -0
- data/spec/download_with_mocks_spec.rb +216 -0
- data/spec/downloader_spec.rb +774 -0
- data/spec/fixtures/first_video_info.json +19 -0
- data/spec/fixtures/rickroll_full_info.json +73 -0
- data/spec/fixtures/rickroll_info.json +73 -0
- data/spec/fixtures/rickroll_segment_info.json +9 -0
- data/spec/integration/ytdlp_integration_spec.rb +109 -0
- data/spec/real_download_spec.rb +175 -0
- data/spec/spec_helper.rb +31 -0
- data/spec/support/fixtures_helper.rb +109 -0
- data/spec/support/mocking_helper.rb +21 -0
- data/spec/support/webmock_helper.rb +132 -0
- data/spec/youtube_rb_spec.rb +200 -0
- data/spec/ytdlp_wrapper_spec.rb +178 -0
- data/youtube-rb.gemspec +39 -0
- metadata +229 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "jNQXAC9IVRw",
|
|
3
|
+
"title": null,
|
|
4
|
+
"fulltitle": null,
|
|
5
|
+
"description": null,
|
|
6
|
+
"uploader": null,
|
|
7
|
+
"uploader_id": null,
|
|
8
|
+
"duration": null,
|
|
9
|
+
"duration_formatted": null,
|
|
10
|
+
"view_count": null,
|
|
11
|
+
"like_count": null,
|
|
12
|
+
"upload_date": null,
|
|
13
|
+
"thumbnail": "https://i.ytimg.com/vi/jNQXAC9IVRw/maxresdefault.jpg",
|
|
14
|
+
"formats": [],
|
|
15
|
+
"subtitles": {},
|
|
16
|
+
"url": null,
|
|
17
|
+
"ext": "mp4",
|
|
18
|
+
"webpage_url": "https://www.youtube.com/watch?v=jNQXAC9IVRw"
|
|
19
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "dQw4w9WgXcQ",
|
|
3
|
+
"title": "Rick Astley - Never Gonna Give You Up (Official Video) (4K Remaster)",
|
|
4
|
+
"fulltitle": "Rick Astley - Never Gonna Give You Up (Official Video) (4K Remaster)",
|
|
5
|
+
"description": "The official video for “Never Gonna Give You Up” by Rick Astley. \n\nNever: The Autobiography 📚 OUT NOW! \nFollow this link to get your copy and listen to Rick’s ‘Never’ playlist ❤️ #RickAstleyNever\nhttps://linktr.ee/rickastleynever\n\n“Never Gonna Give You Up” was a global smash on its release in July 1987, topping the charts in 25 countries including Rick’s native UK and the US Billboard Hot 100. It also won the Brit Award for Best single in 1988. Stock Aitken and Waterman wrote and produced the track which was the lead-off single and lead track from Rick’s debut LP “Whenever You Need Somebody”. The album was itself a UK number one and would go on to sell over 15 million copies worldwide.\n\nThe legendary video was directed by Simon West – who later went on to make Hollywood blockbusters such as Con Air, Lara Croft – Tomb Raider and The Expendables 2. The video passed the 1bn YouTube views milestone on 28 July 2021.\n\nSubscribe to the official Rick Astley YouTube channel: https://RickAstley.lnk.to/YTSubID\n\nFollow Rick Astley:\nFacebook: https://RickAstley.lnk.to/FBFollowID \nTwitter: https://RickAstley.lnk.to/TwitterID \nInstagram: https://RickAstley.lnk.to/InstagramID \nWebsite: https://RickAstley.lnk.to/storeID \nTikTok: https://RickAstley.lnk.to/TikTokID\n\nListen to Rick Astley:\nSpotify: https://RickAstley.lnk.to/SpotifyID \nApple Music: https://RickAstley.lnk.to/AppleMusicID \nAmazon Music: https://RickAstley.lnk.to/AmazonMusicID \nDeezer: https://RickAstley.lnk.to/DeezerID \n\nLyrics:\nWe’re no strangers to love\nYou know the rules and so do I\nA full commitment’s what I’m thinking of\nYou wouldn’t get this from any other guy\n\nI just wanna tell you how I’m feeling\nGotta make you understand\n\nNever gonna give you up\nNever gonna let you down\nNever gonna run around and desert you\nNever gonna make you cry\nNever gonna say goodbye\nNever gonna tell a lie and hurt you\n\nWe’ve known each other for so long\nYour heart’s been aching but you’re too shy to say it\nInside we both know what’s been going on\nWe know the game and we’re gonna play it\n\nAnd if you ask me how I’m feeling\nDon’t tell me you’re too blind to see\n\nNever gonna give you up\nNever gonna let you down\nNever gonna run around and desert you\nNever gonna make you cry\nNever gonna say goodbye\nNever gonna tell a lie and hurt you\n\n#RickAstley #NeverGonnaGiveYouUp #WheneverYouNeedSomebody #OfficialMusicVideo",
|
|
6
|
+
"uploader": "Rick Astley",
|
|
7
|
+
"uploader_id": "UCuAXFkgsw1L7xaCfnd5JJOw",
|
|
8
|
+
"duration": 213,
|
|
9
|
+
"duration_formatted": "03:33",
|
|
10
|
+
"view_count": 1731876521,
|
|
11
|
+
"like_count": null,
|
|
12
|
+
"upload_date": "20091024",
|
|
13
|
+
"thumbnail": "https://i.ytimg.com/vi/dQw4w9WgXcQ/maxresdefault.jpg",
|
|
14
|
+
"formats": [
|
|
15
|
+
{
|
|
16
|
+
"format_id": "18",
|
|
17
|
+
"format_note": "360p",
|
|
18
|
+
"ext": "mp4",
|
|
19
|
+
"url": "https://rr5---sn-ajnv45-5i.googlevideo.com/videoplayback?expire=1768351095&ei=F5Fmae9e0YOL2g-auvwo&ip=84.17.55.134&id=o-AL--MBsb8cncxZtEDEp8FPcv0T2vVhknp-zVZR5x2uTL&itag=18&source=youtube&requiressl=yes&xpc=EgVo2aDSNQ%3D%3D&cps=588&met=1768329495%2C&mh=7c&mm=31%2C29&mn=sn-ajnv45-5i%2Csn-f5f7lne6&ms=au%2Crdu&mv=m&mvi=5&pl=24&rms=au%2Cau&initcwndbps=1267500&bui=AW-iu_r-dXF932QmSV3_zIf4ceyjWpVHA1XLlMbdSfRWXU5baLnjwJq8Hn2pgx9yEDWlq5VXGFv0gfvA&spc=q5xjPGGEKSkdbJQ35FbYATFOOB_n7_qxs7YZRYTs0z44nAInBkTy72V3UGB1e7mRnaReXGLJCQs&vprv=1&svpuc=1&mime=video%2Fmp4&ns=AUNPvmN3_pFD8szzAPSR7cwR&rqh=1&cnr=14&ratebypass=yes&dur=213.089&lmt=1766960953317159&mt=1768328985&fvip=2&fexp=51355912%2C51552689%2C51565115%2C51565681%2C51580968&c=WEB&sefc=1&txp=5538534&n=D6cTu_N-RL9qS7LeDmV&sparams=expire%2Cei%2Cip%2Cid%2Citag%2Csource%2Crequiressl%2Cxpc%2Cbui%2Cspc%2Cvprv%2Csvpuc%2Cmime%2Cns%2Crqh%2Ccnr%2Cratebypass%2Cdur%2Clmt&lsparams=cps%2Cmet%2Cmh%2Cmm%2Cmn%2Cms%2Cmv%2Cmvi%2Cpl%2Crms%2Cinitcwndbps&lsig=APaTxxMwRAIgVrZKRrq9rz36V084NOTnRem5u8hkG7SSopqggSxramECIDZD8DxOPzYb5TJ3Ip-PbHZxnNRHoGfDgB0Krvq12Bat",
|
|
20
|
+
"width": 640,
|
|
21
|
+
"height": 360,
|
|
22
|
+
"fps": 25,
|
|
23
|
+
"vcodec": "avc1.42001E",
|
|
24
|
+
"acodec": "none",
|
|
25
|
+
"tbr": 444,
|
|
26
|
+
"abr": null,
|
|
27
|
+
"vbr": null,
|
|
28
|
+
"filesize": null,
|
|
29
|
+
"quality": "medium",
|
|
30
|
+
"protocol": null
|
|
31
|
+
}
|
|
32
|
+
],
|
|
33
|
+
"subtitles": {
|
|
34
|
+
"en": [
|
|
35
|
+
{
|
|
36
|
+
"ext": "vtt",
|
|
37
|
+
"url": "https://www.youtube.com/api/timedtext?v=dQw4w9WgXcQ&ei=F5Fmae9e0YOL2g-auvwo&caps=asr&opi=112496729&exp=xpe&xoaf=5&xowf=1&hl=pl&ip=0.0.0.0&ipbits=0&expire=1768354695&sparams=ip,ipbits,expire,v,ei,caps,opi,exp,xoaf&signature=5450FAA6D26B1BE8B7E391DC234701C3F175D213.B1A4BFD7E80FB0F99C5F9514356DA1494449C4AB&key=yt8&kind=asr&lang=en",
|
|
38
|
+
"name": "angielski (wygenerowane automatycznie)"
|
|
39
|
+
}
|
|
40
|
+
],
|
|
41
|
+
"es-419": [
|
|
42
|
+
{
|
|
43
|
+
"ext": "vtt",
|
|
44
|
+
"url": "https://www.youtube.com/api/timedtext?v=dQw4w9WgXcQ&ei=F5Fmae9e0YOL2g-auvwo&caps=asr&opi=112496729&exp=xpe&xoaf=5&xowf=1&hl=pl&ip=0.0.0.0&ipbits=0&expire=1768354695&sparams=ip,ipbits,expire,v,ei,caps,opi,exp,xoaf&signature=5450FAA6D26B1BE8B7E391DC234701C3F175D213.B1A4BFD7E80FB0F99C5F9514356DA1494449C4AB&key=yt8&lang=es-419",
|
|
45
|
+
"name": "hiszpański (Ameryka Łacińska)"
|
|
46
|
+
}
|
|
47
|
+
],
|
|
48
|
+
"ja": [
|
|
49
|
+
{
|
|
50
|
+
"ext": "vtt",
|
|
51
|
+
"url": "https://www.youtube.com/api/timedtext?v=dQw4w9WgXcQ&ei=F5Fmae9e0YOL2g-auvwo&caps=asr&opi=112496729&exp=xpe&xoaf=5&xowf=1&hl=pl&ip=0.0.0.0&ipbits=0&expire=1768354695&sparams=ip,ipbits,expire,v,ei,caps,opi,exp,xoaf&signature=5450FAA6D26B1BE8B7E391DC234701C3F175D213.B1A4BFD7E80FB0F99C5F9514356DA1494449C4AB&key=yt8&lang=ja",
|
|
52
|
+
"name": "japoński"
|
|
53
|
+
}
|
|
54
|
+
],
|
|
55
|
+
"de-DE": [
|
|
56
|
+
{
|
|
57
|
+
"ext": "vtt",
|
|
58
|
+
"url": "https://www.youtube.com/api/timedtext?v=dQw4w9WgXcQ&ei=F5Fmae9e0YOL2g-auvwo&caps=asr&opi=112496729&exp=xpe&xoaf=5&xowf=1&hl=pl&ip=0.0.0.0&ipbits=0&expire=1768354695&sparams=ip,ipbits,expire,v,ei,caps,opi,exp,xoaf&signature=5450FAA6D26B1BE8B7E391DC234701C3F175D213.B1A4BFD7E80FB0F99C5F9514356DA1494449C4AB&key=yt8&lang=de-DE",
|
|
59
|
+
"name": "niemiecki (Niemcy)"
|
|
60
|
+
}
|
|
61
|
+
],
|
|
62
|
+
"pt-BR": [
|
|
63
|
+
{
|
|
64
|
+
"ext": "vtt",
|
|
65
|
+
"url": "https://www.youtube.com/api/timedtext?v=dQw4w9WgXcQ&ei=F5Fmae9e0YOL2g-auvwo&caps=asr&opi=112496729&exp=xpe&xoaf=5&xowf=1&hl=pl&ip=0.0.0.0&ipbits=0&expire=1768354695&sparams=ip,ipbits,expire,v,ei,caps,opi,exp,xoaf&signature=5450FAA6D26B1BE8B7E391DC234701C3F175D213.B1A4BFD7E80FB0F99C5F9514356DA1494449C4AB&key=yt8&lang=pt-BR",
|
|
66
|
+
"name": "portugalski (Brazylia)"
|
|
67
|
+
}
|
|
68
|
+
]
|
|
69
|
+
},
|
|
70
|
+
"url": null,
|
|
71
|
+
"ext": "mp4",
|
|
72
|
+
"webpage_url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
|
|
73
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "dQw4w9WgXcQ",
|
|
3
|
+
"title": "Rick Astley - Never Gonna Give You Up (Official Video) (4K Remaster)",
|
|
4
|
+
"fulltitle": "Rick Astley - Never Gonna Give You Up (Official Video) (4K Remaster)",
|
|
5
|
+
"description": "The official video for “Never Gonna Give You Up” by Rick Astley. \n\nNever: The Autobiography 📚 OUT NOW! \nFollow this link to get your copy and listen to Rick’s ‘Never’ playlist ❤️ #RickAstleyNever\nhttps://linktr.ee/rickastleynever\n\n“Never Gonna Give You Up” was a global smash on its release in July 1987, topping the charts in 25 countries including Rick’s native UK and the US Billboard Hot 100. It also won the Brit Award for Best single in 1988. Stock Aitken and Waterman wrote and produced the track which was the lead-off single and lead track from Rick’s debut LP “Whenever You Need Somebody”. The album was itself a UK number one and would go on to sell over 15 million copies worldwide.\n\nThe legendary video was directed by Simon West – who later went on to make Hollywood blockbusters such as Con Air, Lara Croft – Tomb Raider and The Expendables 2. The video passed the 1bn YouTube views milestone on 28 July 2021.\n\nSubscribe to the official Rick Astley YouTube channel: https://RickAstley.lnk.to/YTSubID\n\nFollow Rick Astley:\nFacebook: https://RickAstley.lnk.to/FBFollowID \nTwitter: https://RickAstley.lnk.to/TwitterID \nInstagram: https://RickAstley.lnk.to/InstagramID \nWebsite: https://RickAstley.lnk.to/storeID \nTikTok: https://RickAstley.lnk.to/TikTokID\n\nListen to Rick Astley:\nSpotify: https://RickAstley.lnk.to/SpotifyID \nApple Music: https://RickAstley.lnk.to/AppleMusicID \nAmazon Music: https://RickAstley.lnk.to/AmazonMusicID \nDeezer: https://RickAstley.lnk.to/DeezerID \n\nLyrics:\nWe’re no strangers to love\nYou know the rules and so do I\nA full commitment’s what I’m thinking of\nYou wouldn’t get this from any other guy\n\nI just wanna tell you how I’m feeling\nGotta make you understand\n\nNever gonna give you up\nNever gonna let you down\nNever gonna run around and desert you\nNever gonna make you cry\nNever gonna say goodbye\nNever gonna tell a lie and hurt you\n\nWe’ve known each other for so long\nYour heart’s been aching but you’re too shy to say it\nInside we both know what’s been going on\nWe know the game and we’re gonna play it\n\nAnd if you ask me how I’m feeling\nDon’t tell me you’re too blind to see\n\nNever gonna give you up\nNever gonna let you down\nNever gonna run around and desert you\nNever gonna make you cry\nNever gonna say goodbye\nNever gonna tell a lie and hurt you\n\n#RickAstley #NeverGonnaGiveYouUp #WheneverYouNeedSomebody #OfficialMusicVideo",
|
|
6
|
+
"uploader": "Rick Astley",
|
|
7
|
+
"uploader_id": "UCuAXFkgsw1L7xaCfnd5JJOw",
|
|
8
|
+
"duration": 213,
|
|
9
|
+
"duration_formatted": "03:33",
|
|
10
|
+
"view_count": 1731843872,
|
|
11
|
+
"like_count": null,
|
|
12
|
+
"upload_date": "20091024",
|
|
13
|
+
"thumbnail": "https://i.ytimg.com/vi/dQw4w9WgXcQ/maxresdefault.jpg",
|
|
14
|
+
"formats": [
|
|
15
|
+
{
|
|
16
|
+
"format_id": "18",
|
|
17
|
+
"format_note": "360p",
|
|
18
|
+
"ext": "mp4",
|
|
19
|
+
"url": "https://rr2---sn-f5fz7n7s.googlevideo.com/videoplayback?expire=1768343011&ei=g3FmaeR5y8yL2g_7l-eICg&ip=84.17.55.134&id=o-AE_TGtR6vcKbP3dr7x-UwzmksgxC5mDvndWL4yKnJcGX&itag=18&source=youtube&requiressl=yes&xpc=EgVo2aDSNQ%3D%3D&cps=580&met=1768321411%2C&mh=7c&mm=31%2C29&mn=sn-f5fz7n7s%2Csn-f5f7lne6&ms=au%2Crdu&mv=m&mvi=2&pl=24&rms=au%2Cau&initcwndbps=1967500&bui=AW-iu_r1vGJg5psIN1fOQmXjtOJDTyl_Qs9ozb7L9IvAaC8imT4-6cML3VrA2Q1ckNlfcejY5ep9U6B6&spc=q5xjPBGNQjcm0cdbotZ4tn3XKssBgI1Dq_exNgLyK_KWOFpwdb8_gMXQRA-PchA94s4uqWzaIgE&vprv=1&svpuc=1&mime=video%2Fmp4&ns=Y-oEpOukfySV7nbk3a7i1rsR&rqh=1&cnr=14&ratebypass=yes&dur=213.089&lmt=1766960953317159&mt=1768321065&fvip=2&fexp=51355912%2C51552689%2C51565116%2C51565681%2C51580968&c=WEB&sefc=1&txp=5538534&n=tRZoC9ArNiWHnSdmOBs&sparams=expire%2Cei%2Cip%2Cid%2Citag%2Csource%2Crequiressl%2Cxpc%2Cbui%2Cspc%2Cvprv%2Csvpuc%2Cmime%2Cns%2Crqh%2Ccnr%2Cratebypass%2Cdur%2Clmt&lsparams=cps%2Cmet%2Cmh%2Cmm%2Cmn%2Cms%2Cmv%2Cmvi%2Cpl%2Crms%2Cinitcwndbps&lsig=APaTxxMwRQIhAORAeBYJJ1XQIXAMTMbRQW5tf70o3VlzCYAPTD-1BjujAiB7g_MBsDJjLYZ16RHf7bcMT1A1JkzkRMDIsRtHMfDkLg%3D%3D",
|
|
20
|
+
"width": 640,
|
|
21
|
+
"height": 360,
|
|
22
|
+
"fps": 25,
|
|
23
|
+
"vcodec": "avc1.42001E",
|
|
24
|
+
"acodec": "none",
|
|
25
|
+
"tbr": 444,
|
|
26
|
+
"abr": null,
|
|
27
|
+
"vbr": null,
|
|
28
|
+
"filesize": null,
|
|
29
|
+
"quality": "medium",
|
|
30
|
+
"protocol": null
|
|
31
|
+
}
|
|
32
|
+
],
|
|
33
|
+
"subtitles": {
|
|
34
|
+
"en": [
|
|
35
|
+
{
|
|
36
|
+
"ext": "vtt",
|
|
37
|
+
"url": "https://www.youtube.com/api/timedtext?v=dQw4w9WgXcQ&ei=g3FmaeR5y8yL2g_7l-eICg&caps=asr&opi=112496729&exp=xpe&xoaf=5&xowf=1&hl=pl&ip=0.0.0.0&ipbits=0&expire=1768346611&sparams=ip,ipbits,expire,v,ei,caps,opi,exp,xoaf&signature=90D718CF0CA0629C15CB69C577AA8A9892F1224B.78A7E051DF5A825124E320FFCA6557CAD9A00BB6&key=yt8&kind=asr&lang=en",
|
|
38
|
+
"name": "angielski (wygenerowane automatycznie)"
|
|
39
|
+
}
|
|
40
|
+
],
|
|
41
|
+
"es-419": [
|
|
42
|
+
{
|
|
43
|
+
"ext": "vtt",
|
|
44
|
+
"url": "https://www.youtube.com/api/timedtext?v=dQw4w9WgXcQ&ei=g3FmaeR5y8yL2g_7l-eICg&caps=asr&opi=112496729&exp=xpe&xoaf=5&xowf=1&hl=pl&ip=0.0.0.0&ipbits=0&expire=1768346611&sparams=ip,ipbits,expire,v,ei,caps,opi,exp,xoaf&signature=90D718CF0CA0629C15CB69C577AA8A9892F1224B.78A7E051DF5A825124E320FFCA6557CAD9A00BB6&key=yt8&lang=es-419",
|
|
45
|
+
"name": "hiszpański (Ameryka Łacińska)"
|
|
46
|
+
}
|
|
47
|
+
],
|
|
48
|
+
"ja": [
|
|
49
|
+
{
|
|
50
|
+
"ext": "vtt",
|
|
51
|
+
"url": "https://www.youtube.com/api/timedtext?v=dQw4w9WgXcQ&ei=g3FmaeR5y8yL2g_7l-eICg&caps=asr&opi=112496729&exp=xpe&xoaf=5&xowf=1&hl=pl&ip=0.0.0.0&ipbits=0&expire=1768346611&sparams=ip,ipbits,expire,v,ei,caps,opi,exp,xoaf&signature=90D718CF0CA0629C15CB69C577AA8A9892F1224B.78A7E051DF5A825124E320FFCA6557CAD9A00BB6&key=yt8&lang=ja",
|
|
52
|
+
"name": "japoński"
|
|
53
|
+
}
|
|
54
|
+
],
|
|
55
|
+
"de-DE": [
|
|
56
|
+
{
|
|
57
|
+
"ext": "vtt",
|
|
58
|
+
"url": "https://www.youtube.com/api/timedtext?v=dQw4w9WgXcQ&ei=g3FmaeR5y8yL2g_7l-eICg&caps=asr&opi=112496729&exp=xpe&xoaf=5&xowf=1&hl=pl&ip=0.0.0.0&ipbits=0&expire=1768346611&sparams=ip,ipbits,expire,v,ei,caps,opi,exp,xoaf&signature=90D718CF0CA0629C15CB69C577AA8A9892F1224B.78A7E051DF5A825124E320FFCA6557CAD9A00BB6&key=yt8&lang=de-DE",
|
|
59
|
+
"name": "niemiecki (Niemcy)"
|
|
60
|
+
}
|
|
61
|
+
],
|
|
62
|
+
"pt-BR": [
|
|
63
|
+
{
|
|
64
|
+
"ext": "vtt",
|
|
65
|
+
"url": "https://www.youtube.com/api/timedtext?v=dQw4w9WgXcQ&ei=g3FmaeR5y8yL2g_7l-eICg&caps=asr&opi=112496729&exp=xpe&xoaf=5&xowf=1&hl=pl&ip=0.0.0.0&ipbits=0&expire=1768346611&sparams=ip,ipbits,expire,v,ei,caps,opi,exp,xoaf&signature=90D718CF0CA0629C15CB69C577AA8A9892F1224B.78A7E051DF5A825124E320FFCA6557CAD9A00BB6&key=yt8&lang=pt-BR",
|
|
66
|
+
"name": "portugalski (Brazylia)"
|
|
67
|
+
}
|
|
68
|
+
]
|
|
69
|
+
},
|
|
70
|
+
"url": null,
|
|
71
|
+
"ext": "mp4",
|
|
72
|
+
"webpage_url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
|
|
73
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
|
|
3
|
+
"video_id": "dQw4w9WgXcQ",
|
|
4
|
+
"start_time": 10,
|
|
5
|
+
"end_time": 25,
|
|
6
|
+
"duration": 15,
|
|
7
|
+
"file_size": 19311959,
|
|
8
|
+
"output_file": "Rick Astley - Never Gonna Give You Up (Official Video) (4K Remaster)-dQw4w9WgXcQ.webm"
|
|
9
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# Integration tests for yt-dlp backend
|
|
2
|
+
# These tests require yt-dlp to be installed and an internet connection
|
|
3
|
+
# Run with: bundle exec rspec spec/integration --tag integration
|
|
4
|
+
|
|
5
|
+
RSpec.describe "YoutubeRb + yt-dlp Integration", :integration do
|
|
6
|
+
# Test URL - Rick Astley (public domain, always available)
|
|
7
|
+
let(:test_url) { 'https://www.youtube.com/watch?v=dQw4w9WgXcQ' }
|
|
8
|
+
let(:test_video_id) { 'dQw4w9WgXcQ' }
|
|
9
|
+
|
|
10
|
+
before(:all) do
|
|
11
|
+
@client = YoutubeRb::Client.new
|
|
12
|
+
@deps = @client.check_dependencies
|
|
13
|
+
|
|
14
|
+
unless @deps[:ytdlp]
|
|
15
|
+
skip "yt-dlp is not installed. Install with: pip install -U yt-dlp"
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
describe "dependency check" do
|
|
20
|
+
it "detects yt-dlp installation" do
|
|
21
|
+
expect(@deps[:ytdlp]).to be true
|
|
22
|
+
expect(@deps[:ytdlp_version]).to be_a(String)
|
|
23
|
+
expect(@deps[:ytdlp_version]).not_to eq('not installed')
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it "reports yt-dlp version" do
|
|
27
|
+
expect(@deps[:ytdlp_version]).to match(/\d+\.\d+\.\d+/)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
describe "video information extraction" do
|
|
32
|
+
it "extracts video info using default client" do
|
|
33
|
+
info = YoutubeRb.info(test_url)
|
|
34
|
+
|
|
35
|
+
expect(info).to be_a(YoutubeRb::VideoInfo)
|
|
36
|
+
expect(info.id).to eq(test_video_id)
|
|
37
|
+
expect(info.title).to include('Rick Astley')
|
|
38
|
+
expect(info.duration).to be > 0
|
|
39
|
+
expect(info.uploader).not_to be_nil
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it "extracts info with yt-dlp wrapper directly" do
|
|
43
|
+
wrapper = YoutubeRb::YtdlpWrapper.new
|
|
44
|
+
info = wrapper.extract_info(test_url)
|
|
45
|
+
|
|
46
|
+
expect(info).to be_a(Hash)
|
|
47
|
+
expect(info['id']).to eq(test_video_id)
|
|
48
|
+
expect(info['title']).to be_a(String)
|
|
49
|
+
expect(info['duration']).to be_a(Integer)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
describe "backend selection" do
|
|
54
|
+
it "creates client with yt-dlp backend enabled" do
|
|
55
|
+
client = YoutubeRb::Client.new(use_ytdlp: true, verbose: false)
|
|
56
|
+
expect(client.options.use_ytdlp).to be true
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it "creates client with fallback mode" do
|
|
60
|
+
client = YoutubeRb::Client.new(ytdlp_fallback: true, verbose: false)
|
|
61
|
+
expect(client.options.ytdlp_fallback).to be true
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
it "creates client with verbose mode" do
|
|
65
|
+
client = YoutubeRb::Client.new(verbose: true)
|
|
66
|
+
expect(client.options.verbose).to be true
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
describe "YtdlpWrapper availability" do
|
|
71
|
+
it "reports availability correctly" do
|
|
72
|
+
expect(YoutubeRb::YtdlpWrapper.available?).to be true
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
it "returns version string" do
|
|
76
|
+
version = YoutubeRb::YtdlpWrapper.version
|
|
77
|
+
expect(version).to be_a(String)
|
|
78
|
+
expect(version).not_to be_empty
|
|
79
|
+
expect(version).not_to eq('not installed')
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
describe "download with yt-dlp (slow)", :slow do
|
|
84
|
+
let(:output_dir) { './spec/tmp/downloads' }
|
|
85
|
+
|
|
86
|
+
before(:each) do
|
|
87
|
+
FileUtils.mkdir_p(output_dir)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
after(:each) do
|
|
91
|
+
FileUtils.rm_rf(output_dir) if Dir.exist?(output_dir)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
it "downloads video segment using yt-dlp backend" do
|
|
95
|
+
client = YoutubeRb::Client.new(
|
|
96
|
+
output_path: output_dir,
|
|
97
|
+
use_ytdlp: true,
|
|
98
|
+
verbose: false
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
# Download just the first 10 seconds to speed up test
|
|
102
|
+
output_file = client.download_segment(test_url, 0, 10)
|
|
103
|
+
|
|
104
|
+
expect(output_file).to be_a(String)
|
|
105
|
+
expect(File.exist?(output_file)).to be true
|
|
106
|
+
expect(File.size(output_file)).to be > 0
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# Real download tests - require internet connection and yt-dlp
|
|
2
|
+
# Run with: bundle exec rspec spec/real_download_spec.rb --tag real_download
|
|
3
|
+
# These tests actually download videos from YouTube
|
|
4
|
+
|
|
5
|
+
RSpec.describe "Real video downloads", :real_download do
|
|
6
|
+
let(:output_dir) { './spec/tmp/real_downloads' }
|
|
7
|
+
|
|
8
|
+
before(:all) do
|
|
9
|
+
# Allow real HTTP connections for these tests
|
|
10
|
+
WebMock.allow_net_connect!
|
|
11
|
+
|
|
12
|
+
# Check if yt-dlp is available
|
|
13
|
+
unless YoutubeRb::YtdlpWrapper.available?
|
|
14
|
+
skip "yt-dlp is not installed. Install with: pip install -U yt-dlp"
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
after(:all) do
|
|
19
|
+
# Restore WebMock behavior
|
|
20
|
+
WebMock.disable_net_connect!(allow_localhost: true)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
before(:each) do
|
|
24
|
+
FileUtils.mkdir_p(output_dir)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
after(:each) do
|
|
28
|
+
# Clean up downloaded files
|
|
29
|
+
FileUtils.rm_rf(output_dir) if Dir.exist?(output_dir)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
describe "Rick Astley - Never Gonna Give You Up" do
|
|
33
|
+
# Rick Astley video works without cookies
|
|
34
|
+
let(:rickroll_url) { 'https://www.youtube.com/watch?v=dQw4w9WgXcQ' }
|
|
35
|
+
let(:rickroll_id) { 'dQw4w9WgXcQ' }
|
|
36
|
+
|
|
37
|
+
it "extracts full video information" do
|
|
38
|
+
puts "\n → Testing video info extraction for Rick Astley"
|
|
39
|
+
|
|
40
|
+
info = YoutubeRb.info(rickroll_url)
|
|
41
|
+
|
|
42
|
+
expect(info).to be_a(YoutubeRb::VideoInfo)
|
|
43
|
+
expect(info.id).to eq(rickroll_id)
|
|
44
|
+
expect(info.title).to include('Never Gonna Give You Up')
|
|
45
|
+
expect(info.duration).to eq(213)
|
|
46
|
+
expect(info.uploader).to eq('Rick Astley')
|
|
47
|
+
|
|
48
|
+
puts " ✓ Title: #{info.title}"
|
|
49
|
+
puts " ✓ Duration: #{info.duration} seconds"
|
|
50
|
+
puts " ✓ Uploader: #{info.uploader}"
|
|
51
|
+
|
|
52
|
+
# Save the response for mocking later
|
|
53
|
+
File.write('./spec/fixtures/rickroll_full_info.json', JSON.pretty_generate(info.to_h))
|
|
54
|
+
puts " ✓ Saved response to spec/fixtures/rickroll_full_info.json for mocking"
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
it "downloads 15-second segment from 10 to 25 seconds" do
|
|
58
|
+
puts "\n → Testing segment download: Rick Astley (10-25 sec)"
|
|
59
|
+
puts " → This will download ~14MB of video segment..."
|
|
60
|
+
|
|
61
|
+
start_time = 10
|
|
62
|
+
end_time = 25
|
|
63
|
+
|
|
64
|
+
client = YoutubeRb::Client.new(
|
|
65
|
+
output_path: output_dir,
|
|
66
|
+
use_ytdlp: true,
|
|
67
|
+
verbose: true
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
output_file = client.download_segment(rickroll_url, start_time, end_time)
|
|
71
|
+
|
|
72
|
+
# Verify download
|
|
73
|
+
expect(output_file).to be_a(String)
|
|
74
|
+
expect(File.exist?(output_file)).to be true
|
|
75
|
+
expect(File.size(output_file)).to be > 50_000 # At least 50KB for 15 sec
|
|
76
|
+
|
|
77
|
+
# Verify segment duration using ffprobe if available
|
|
78
|
+
if system('which ffprobe > /dev/null 2>&1')
|
|
79
|
+
duration_cmd = "ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 '#{output_file}'"
|
|
80
|
+
duration = `#{duration_cmd}`.strip.to_f
|
|
81
|
+
|
|
82
|
+
# Duration should be approximately 15 seconds (allow generous variance)
|
|
83
|
+
# NOTE: Without re-encoding (--force-keyframes-at-cuts), yt-dlp cuts at keyframes only,
|
|
84
|
+
# which can result in segments being a few seconds longer than requested.
|
|
85
|
+
# This is acceptable for performance reasons - cutting at keyframes is 10x faster.
|
|
86
|
+
# Expected: 15 seconds, but may be 20-30 seconds due to keyframe positions.
|
|
87
|
+
expect(duration).to be_between(10, 30)
|
|
88
|
+
puts " ✓ Segment duration: #{duration.round(1)} seconds (requested: 15s)"
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
puts " ✓ Downloaded to: #{output_file}"
|
|
92
|
+
puts " ✓ File size: #{(File.size(output_file) / 1024.0).round(2)} KB"
|
|
93
|
+
|
|
94
|
+
# Save info about what we downloaded for mocking
|
|
95
|
+
segment_info = {
|
|
96
|
+
url: rickroll_url,
|
|
97
|
+
video_id: rickroll_id,
|
|
98
|
+
start_time: start_time,
|
|
99
|
+
end_time: end_time,
|
|
100
|
+
duration: end_time - start_time,
|
|
101
|
+
file_size: File.size(output_file),
|
|
102
|
+
output_file: File.basename(output_file)
|
|
103
|
+
}
|
|
104
|
+
File.write('./spec/fixtures/rickroll_segment_info.json', JSON.pretty_generate(segment_info))
|
|
105
|
+
puts " ✓ Saved segment info to spec/fixtures/rickroll_segment_info.json"
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
it "downloads full video using yt-dlp backend", :very_slow do
|
|
109
|
+
puts "\n → Testing full video download: Rick Astley (dQw4w9WgXcQ)"
|
|
110
|
+
puts " → This will download ~240MB of video data..."
|
|
111
|
+
puts " → This may take a few minutes depending on your connection..."
|
|
112
|
+
|
|
113
|
+
client = YoutubeRb::Client.new(
|
|
114
|
+
output_path: output_dir,
|
|
115
|
+
use_ytdlp: true,
|
|
116
|
+
verbose: true
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
output_file = client.download(rickroll_url)
|
|
120
|
+
|
|
121
|
+
# Verify download
|
|
122
|
+
expect(output_file).to be_a(String)
|
|
123
|
+
expect(File.exist?(output_file)).to be true
|
|
124
|
+
expect(File.size(output_file)).to be > 10_000_000 # At least 10MB
|
|
125
|
+
|
|
126
|
+
puts " ✓ Downloaded to: #{output_file}"
|
|
127
|
+
puts " ✓ File size: #{(File.size(output_file) / 1024.0 / 1024.0).round(2)} MB"
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
describe "fallback mechanism" do
|
|
132
|
+
let(:test_url) { 'https://www.youtube.com/watch?v=dQw4w9WgXcQ' }
|
|
133
|
+
|
|
134
|
+
it "falls back to yt-dlp when pure Ruby fails", :very_slow do
|
|
135
|
+
puts "\n → Testing automatic fallback to yt-dlp"
|
|
136
|
+
puts " → This may download ~240MB of video data..."
|
|
137
|
+
|
|
138
|
+
client = YoutubeRb::Client.new(
|
|
139
|
+
output_path: output_dir,
|
|
140
|
+
use_ytdlp: false, # Start with pure Ruby
|
|
141
|
+
ytdlp_fallback: true, # Enable fallback
|
|
142
|
+
verbose: true
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
# This should try pure Ruby first, then fall back to yt-dlp
|
|
146
|
+
output_file = client.download(test_url)
|
|
147
|
+
|
|
148
|
+
expect(output_file).to be_a(String)
|
|
149
|
+
expect(File.exist?(output_file)).to be true
|
|
150
|
+
expect(File.size(output_file)).to be > 10_000_000 # At least 10MB
|
|
151
|
+
|
|
152
|
+
puts " ✓ Fallback worked, file downloaded"
|
|
153
|
+
puts " ✓ File size: #{(File.size(output_file) / 1024.0 / 1024.0).round(2)} MB"
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
describe "error handling" do
|
|
158
|
+
it "raises error for invalid video ID" do
|
|
159
|
+
puts "\n → Testing error handling for invalid video"
|
|
160
|
+
|
|
161
|
+
client = YoutubeRb::Client.new(
|
|
162
|
+
output_path: output_dir,
|
|
163
|
+
use_ytdlp: true
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
invalid_url = 'https://www.youtube.com/watch?v=invalidvideoid'
|
|
167
|
+
|
|
168
|
+
expect {
|
|
169
|
+
client.download(invalid_url)
|
|
170
|
+
}.to raise_error(YoutubeRb::Downloader::DownloadError)
|
|
171
|
+
|
|
172
|
+
puts " ✓ Correctly raised error for invalid video"
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
require "youtube-rb"
|
|
2
|
+
require "webmock/rspec"
|
|
3
|
+
require "tmpdir"
|
|
4
|
+
require "fileutils"
|
|
5
|
+
|
|
6
|
+
# Allow connections to stubbed URLs only
|
|
7
|
+
WebMock.disable_net_connect!(allow_localhost: false)
|
|
8
|
+
|
|
9
|
+
RSpec.configure do |config|
|
|
10
|
+
# Enable flags like --only-failures and --next-failure
|
|
11
|
+
config.example_status_persistence_file_path = ".rspec_status"
|
|
12
|
+
|
|
13
|
+
# Disable RSpec exposing methods globally on `Module` and `main`
|
|
14
|
+
config.disable_monkey_patching!
|
|
15
|
+
|
|
16
|
+
config.expect_with :rspec do |c|
|
|
17
|
+
c.syntax = :expect
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Load support files
|
|
21
|
+
Dir[File.join(__dir__, "support", "**", "*.rb")].sort.each { |f| require f }
|
|
22
|
+
|
|
23
|
+
# Clean up test downloads before each test
|
|
24
|
+
config.before(:each) do
|
|
25
|
+
@test_output_dir = Dir.mktmpdir('youtube-rb-test')
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
config.after(:each) do
|
|
29
|
+
FileUtils.rm_rf(@test_output_dir) if @test_output_dir && Dir.exist?(@test_output_dir)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
module FixturesHelper
|
|
2
|
+
def fixture_path(filename)
|
|
3
|
+
File.join(__dir__, '..', 'fixtures', filename)
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
def load_fixture(filename)
|
|
7
|
+
File.read(fixture_path(filename))
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def load_json_fixture(filename)
|
|
11
|
+
JSON.parse(load_fixture(filename))
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Real data from rickroll video
|
|
15
|
+
def rickroll_video_info
|
|
16
|
+
@rickroll_video_info ||= load_json_fixture('rickroll_info.json')
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Sample video data for testing
|
|
20
|
+
def sample_video_data
|
|
21
|
+
{
|
|
22
|
+
'id' => 'test123abc',
|
|
23
|
+
'title' => 'Test Video Title',
|
|
24
|
+
'fulltitle' => 'Test Video Title',
|
|
25
|
+
'description' => 'This is a test video description',
|
|
26
|
+
'uploader' => 'Test Channel',
|
|
27
|
+
'uploader_id' => 'UC1234567890',
|
|
28
|
+
'duration' => 180,
|
|
29
|
+
'view_count' => 1000,
|
|
30
|
+
'like_count' => 50,
|
|
31
|
+
'upload_date' => '20240101',
|
|
32
|
+
'thumbnail' => 'https://example.com/thumbnail.jpg',
|
|
33
|
+
'ext' => 'mp4',
|
|
34
|
+
'webpage_url' => 'https://www.youtube.com/watch?v=test123abc',
|
|
35
|
+
'formats' => [
|
|
36
|
+
{
|
|
37
|
+
'format_id' => '18',
|
|
38
|
+
'ext' => 'mp4',
|
|
39
|
+
'height' => 360,
|
|
40
|
+
'url' => 'https://example.com/video.mp4',
|
|
41
|
+
'vcodec' => 'avc1.42001E',
|
|
42
|
+
'acodec' => 'mp4a.40.2',
|
|
43
|
+
'quality' => 'medium',
|
|
44
|
+
'tbr' => 500
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
'format_id' => '22',
|
|
48
|
+
'ext' => 'mp4',
|
|
49
|
+
'height' => 720,
|
|
50
|
+
'url' => 'https://example.com/video-720p.mp4',
|
|
51
|
+
'vcodec' => 'avc1.64001F',
|
|
52
|
+
'acodec' => 'mp4a.40.2',
|
|
53
|
+
'quality' => 'hd720',
|
|
54
|
+
'tbr' => 2000
|
|
55
|
+
}
|
|
56
|
+
],
|
|
57
|
+
'subtitles' => {
|
|
58
|
+
'en' => [
|
|
59
|
+
{
|
|
60
|
+
'ext' => 'vtt',
|
|
61
|
+
'url' => 'https://example.com/subtitles-en.vtt',
|
|
62
|
+
'name' => 'English'
|
|
63
|
+
}
|
|
64
|
+
],
|
|
65
|
+
'es' => [
|
|
66
|
+
{
|
|
67
|
+
'ext' => 'vtt',
|
|
68
|
+
'url' => 'https://example.com/subtitles-es.vtt',
|
|
69
|
+
'name' => 'Spanish'
|
|
70
|
+
}
|
|
71
|
+
]
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Sample subtitle content (VTT format)
|
|
77
|
+
def sample_subtitle_vtt
|
|
78
|
+
<<~VTT
|
|
79
|
+
WEBVTT
|
|
80
|
+
|
|
81
|
+
00:00:00.000 --> 00:00:05.000
|
|
82
|
+
Welcome to this test video
|
|
83
|
+
|
|
84
|
+
00:00:05.000 --> 00:00:10.000
|
|
85
|
+
This is a sample subtitle
|
|
86
|
+
|
|
87
|
+
00:00:10.000 --> 00:00:15.000
|
|
88
|
+
Testing subtitle trimming
|
|
89
|
+
|
|
90
|
+
00:00:15.000 --> 00:00:20.000
|
|
91
|
+
End of subtitle test
|
|
92
|
+
VTT
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Sample video binary data (minimal MP4 header)
|
|
96
|
+
def sample_video_binary
|
|
97
|
+
# Minimal valid MP4 file (just ftyp box)
|
|
98
|
+
[
|
|
99
|
+
0x00, 0x00, 0x00, 0x20, 0x66, 0x74, 0x79, 0x70,
|
|
100
|
+
0x69, 0x73, 0x6F, 0x6D, 0x00, 0x00, 0x02, 0x00,
|
|
101
|
+
0x69, 0x73, 0x6F, 0x6D, 0x69, 0x73, 0x6F, 0x32,
|
|
102
|
+
0x61, 0x76, 0x63, 0x31, 0x6D, 0x70, 0x34, 0x31
|
|
103
|
+
].pack('C*')
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
RSpec.configure do |config|
|
|
108
|
+
config.include FixturesHelper
|
|
109
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module MockingHelper
|
|
2
|
+
# Mock the Extractor to return video info without making HTTP requests
|
|
3
|
+
def mock_extractor(video_data)
|
|
4
|
+
video_info = YoutubeRb::VideoInfo.new(video_data)
|
|
5
|
+
|
|
6
|
+
allow_any_instance_of(YoutubeRb::Extractor).to receive(:extract_info).and_return(video_info)
|
|
7
|
+
allow_any_instance_of(YoutubeRb::Extractor).to receive(:extract_formats).and_return(video_data['formats'] || [])
|
|
8
|
+
allow_any_instance_of(YoutubeRb::Extractor).to receive(:extract_subtitles).and_return(video_data['subtitles'] || {})
|
|
9
|
+
|
|
10
|
+
video_info
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Mock extractor to raise error
|
|
14
|
+
def mock_extractor_error(error_class = YoutubeRb::Extractor::ExtractionError, message = 'Test error')
|
|
15
|
+
allow_any_instance_of(YoutubeRb::Extractor).to receive(:extract_info).and_raise(error_class, message)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
RSpec.configure do |config|
|
|
20
|
+
config.include MockingHelper
|
|
21
|
+
end
|