YouTubeKit is a powerful Swift package to make requests to the YouTube API without having any API key.
DocC is available here.
- Install the package to your Xcode project:
- In the top menu go to File->Add Packages...
- Enter the link of this repository: https://github.com/b5i/YouTubeKit (you may have to connect Xcode to your github account).
- Click on
Add Package
. - Use it in your project by importing it:
import YouTubeKit
.
Please note that this is adapted from another iOS app and so is in constant developpement.
Here is a list of the default requests supported by YouTubeKit, all the informations you can get are:
-
HomeScreenResponse -> get videos from the main page of YouTube, its Continuation is also available.
-
SearchResponse -> get results for a text query, its Continuation is also available.
-
SearchResponse.Restricted -> get Creative Commons copyrighted results for a text query.
-
VideoInfosResponse -> get the infos of a video by ID.
-
VideoInfosWithDownloadFormatsResponse -> get the infos of a video by ID and the DownloadFormats, consumes more bandwidth than VideoInfosResponse but has an array of DownloadFormat.
-
AutoCompletionResponse -> get autoCompletion suggestions from a text query.
-
ChannelInfosResponse -> get infos of a YouTube channel by its id.
-
PlaylistInfosResponse -> get a playlist's informations and the videos it contains. Its Continuation is also available.
-
AccountInfosResponse to get the informations about a YouTube account (using the cookies).
-
AccountLibraryResponse to get the library of an account.
-
AllPossibleHostPlaylistsResponse to get all the playlists a video could be added to and if the video is already present inside.
-
AddVideoToPlaylistResponse, CreatePlaylistResponse, DeletePlaylistResponse, MoveVideoInPlaylistResponse, RemoveVideoByIdFromPlaylistResponse and RemoveVideoFromPlaylistResponse to manage an account's playlists.
-
LikeVideoResponse, DislikeVideoResponse and RemoveLikeFromVideoResponse.
-
MoreVideoInfosResponse to get various informations about a video (see documentation).
Every possible request within YouTubeKit conforms to the protocol YouTubeResponse, it contains a few useful methods:
static var headersType
is a static variable indicating the type of headers used to make the request, its documentation indicates which parameter to provide in order to make the request work.static func decodeData(data: Data) -> Self
is a static method used to decode some Data and give back in instance of theYouTubeResponse
, if the Data does not represent a proper response it will return an empty response (only nils and empty arrays).static func sendRequest()
is a static method that allows you to make request, by using async await system or closures. Its usage will be precised in the following tutorial.
With YouTubeKit you can make a large variety of requests to the YouTube API, new request types are added often and you can even create your own in Custom requests/responses.
- Make sure you have an instance of
YouTubeModel
, if not you can create one with
let YTM = YouTubeModel()
-
Define the request's data parameters, to get the demanded headers you can look at the definition of your
YouTubeResponse.headersType
it should describe which data to send. An example with aSearchResponse
:a. Right click on the type of request and press
Jump to definition
, theSearchResponse.headersType
isHeaderTypes.search
.b. Its definition is
/// Get search results. /// - Parameter query: Search query case search
it means that you will have to provide a query for the request to work and give a relevant result.
c. You will define the data parameters like this:
let textQuery: String = "my super query" let dataParameters: [HeadersList.AddQueryInfo.ContentTypes : String] = [ .query: textQuery ]
-
Execute the request with (e.g. a
SearchResponse
request)
SearchResponse.sendRequest(youtubeModel: YTM, data: dataParameters, result: { result, error in
/// Process here the result.
print(result)
/// If the result is nil you should obtain an error explaining why there is one.
print(error)
})
you can also send the request without explicitly declaring dataParameters
like this
SearchResponse.sendRequest(youtubeModel: YTM, data: [.query: textQuery], result: { result, error in
/// Process here the result.
print(result)
/// If the result is nil you should obtain an error explaining why there is one.
print(error)
})
YouTubeKit allows you to add an account's cookies into the requests by following those steps:
- Define the cookies variable in your YouTubeModel:
let YTM = YouTubeModel()
YTM.cookies = "myCookies"
- If you want to always use cookies when making requests you can opt to set the
alwaysUseCookies
of theYouTubeModel
like so:
let YTM = YouTubeModel()
YTM.cookies = "myCookies"
YTM.alwaysUseCookies = true
- You can also choose to use cookies by request by specifying the
useCookies
parameter present in every request function.
A lot of structures and protocol have custom request calls (shortcuts to various YouTubeResponse
), here is a few examples:
1. YouTubeVideo
(YTVideo
conforms to it) has:
1. fetchStreamingInfos
that can be used to retrieve the basic streaming data.
2. fetchStreamingInfosWithDownloadFormats
that is the same as fetchStreamingInfos
but it includes the download formats (all the different video/audio formats you can stream/download the video).
3. fetchMoreInfos
that can be used to retrieve more infos about the video (recommended videos, description with chapters and links, and more!).
4. likeVideo
, dislikeVideo
, removeLikeFromVideo
.
5. fetchAllPossibleHostPlaylists
2. YouTubeChannel
(YTChannel
and YTLittleChannelInfos
are conform to it) has:
1. fetchInfos
that can be used to retrieve various informations about the channel.
3. ResultsResponse
(HomeScreenResponse
, SearchResponse
, PlaylistInfosResponse
are conform to it) has:
1. mergeContinuation
to merge the continuations easily.
2. fetchContinuation
to get those continuations.
To create custom headers and so custom request/response function, you have to:
- Append the function that is used to generate the
HeadersList
inYouTubeModel.customHeadersFunctions
, e.g
let YTM = YouTubeModel()
let myCustomHeadersFunction: () -> HeadersList = {
HeadersList(
url: URL(string: "https://www.myrequesturl.com")!,
method: .POST,
headers: [
.init(name: "Accept", content: "*/*"),
.init(name: "Accept-Encoding", content: "gzip, deflate, br"),
.init(name: "Accept-Language", content: "\(YTM.selectedLocale);q=0.9"),
],
addQueryAfterParts: [
.init(index: 0, encode: true)
],
httpBody: [
"my query is: ",
" and it is really cool!"
]
)
}
YouTubeModel.shared.customHeadersFunctions["myHeadersID"] = myCustomHeadersFunction
- Create the response that is conform to the YouTubeResponse protocol, e.g
/*
We imagine that the JSON is of the form:
{
"name": "myName",
"surname": "mySurname"
}
*/
/// Struct representing a getNameAndSurname response.
public struct NameAndSurnameResponse: YouTubeResponse {
public static var headersType: HeaderTypes = .customHeaders("myHeadersID") //<- the myHeadersID has to be the same as the one you defined in step 1!
/// String representing a name.
public var name: String = ""
/// String representing a surname.
public var surname: String = ""
public static func decodeData(data: Data) -> NameAndSurnameResponse {
/// Initialize an empty response.
var nameAndSurnameResponse = NameAndSurnameResponse()
// Extracts the data of the JSON, can also be done using normal JSONDecoder().decode(NameAndSurnameResponse.self, data) by making NameAndSurnameResponse conform to Codable protocol as the JSON is not very complex here.
let json = JSON(data)
nameAndSurnameResponse.name = json["name"].stringValue
nameAndSurnameResponse.surname = json["surname"].stringValue
return nameAndSurnameResponse
}
}
- And to exectute it you just have to call
func sendRequest<ResponseType: YouTubeResponse>( responseType: ResponseType.Type, data: [HeadersList.AddQueryInfo.ContentTypes : String], result: @escaping (ResponseType?, Error?) -> () )
e.g,
/// We continue with our example:
NameAndSurnameResponse.sendRequest(youtubeModel: YTM, data: [:], result: { result, error in
/// Process here the result.
print(result)
/// If the result is nil you should obtain an error explaining why there is one.
print(error)
})
Note: you would include in the request the parameters if needed like: query, browseId or anything like this to put in the body of the request to send.
This category lists solutions to problems you might encounter with YouTubeKit.
-
Error Domain=NSURLErrorDomain Code=-1003 "A server with the specified hostname could not be found."
This issue can be resolved by enabling the
Outgoing Connections (Client)
in theSigning & Capabilities
category of your project's target in Xcode. -
The download speed is very low when downloading an audio-only
DownloadFormat
: this issue can be resolved by adding therange: bytes=0-(CONTENT_LENGHT_BYTES)
HTTP header to yourURLRequest
(e.g.request.addValue("bytes=0-\(myDownloadFormat.contentLength ?? "")", forHTTPHeaderField: "range")
).
- The result of a request is empty: this issue could be caused by the locale that could be in the wrong format. Make sure that your
YouTubeModel.selectedLocale
is likeen-US
.