Skip to content

Commit

Permalink
Merge pull request #2 from suzuki3jp/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
suzuki3jp authored Jan 19, 2025
2 parents 6c5cb2d + cba9337 commit 4351cb7
Show file tree
Hide file tree
Showing 6 changed files with 148 additions and 10 deletions.
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2024 suzuki3jp
Copyright (c) 2025 suzuki3jp

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ We are striving to support more endpoints, but currently, there are many unsuppo
| [MembershipsLevels](https://developers.google.com/youtube/v3/docs/membershipsLevels) | × | - | - | - |
| [PlaylistImages](https://developers.google.com/youtube/v3/docs/playlistImages) | × | × | × | × |
| [PlaylistItems](https://developers.google.com/youtube/v3/docs/playlistItems) | × | × | × | × |
| [Playlists](https://developers.google.com/youtube/v3/docs/playlists) ||| × ||
| [Playlists](https://developers.google.com/youtube/v3/docs/playlists) ||| ||
| [Search](https://developers.google.com/youtube/v3/docs/search) | × | - | - | - |
| [Subscriptions](https://developers.google.com/youtube/v3/docs/subscriptions) | × | × | - | × |
| [Thumbnails](https://developers.google.com/youtube/v3/docs/thumbnails) | - | × | - | - |
Expand Down
75 changes: 73 additions & 2 deletions docs/02-usecases.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,73 @@
# Use cases
coming soon...
# Use Cases

## Note
All methods in `youtubes.js` return [`Result`](https://github.com/suzuki3jp/result4js) for safe error handling.
Learn more about error handling with `Result` [here](./01-introduction.md#handling-errors).

## Pagination
The YouTube Data API v3 sometimes returns paginated responses.
For such endpoints, `youtubes.js` returns data wrapped in [`Pagination`](../src/Pagination.ts) to simplify requesting additional pages.

```ts
import { ApiClient, StaticOAuthProvider } from "youtubes.js";

const oauth = new StaticOAuthProvider({
accessToken: "ACCESS_TOKEN",
});
const client = new ApiClient({ oauth });

const playlists = await client.playlists.getMine(); // Result<Pagination<Playlist[]>, YouTubesJsErrors>
console.log(playlists.data); // The first page of playlists

// Get the previous page
// Returns null if no previous page exists
const prevPage = await playlists.prev(); // Result<Pagination<Playlist>, YouTubesJsErrors> | null

// Get the next page
// Returns null if no next page exists
const nextPage = await playlists.next(); // Result<Pagination<Playlist>, YouTubesJsErrors> | null

// Get all pages
// **NOTE**: This method may consume unnecessary quotas, so be careful when using it in actual applications.
// We strongly recommend fetching the next page based on user actions (e.g., scrolling).
const allPages = await playlists.all() // Result<Playlist[], YouTubesJsErrors
if (allPages.isErr()) return; // Handling errors
// Returns all pages in an array. For multiple items per page, returns a 2D array.
// Use flat() to convert to a 1D array.
const data = allPages.data.flat();
```

## `Playlists`
To interact with the [`playlists`](https://developers.google.com/youtube/v3/docs/playlists) endpoint, use [`PlaylistManager`](../src/managers/PlaylistManager.ts).

```ts
import { ApiClient, StaticOAuthProvider } from "youtubes.js";

const oauth = new StaticOAuthProvider({
accessToken: "ACCESS_TOKEN",
});
const client = new ApiClient({ oauth });

// You can access to the `PlaylistManager` here.
client.playlists
```

### Retrieving Playlists
You can retrieve playlists using:

- [`PlaylistManager#getMine`](../src/managers/PlaylistManager.ts#L57)
- [`PlaylistManager#getByIds`](../src/managers/PlaylistManager.ts#L109)
- [`PlaylistManager#getByChannelId`](../src/managers/PlaylistManager.ts#L162)

```ts
import { ApiClient, StaticOAuthProvider } from "youtubes.js";

const oauth = new StaticOAuthProvider({
accessToken: "ACCESS_TOKEN",
});
const client = new ApiClient({ oauth });

const myPlaylists = await client.playlists.getMine(); // Result<Pagination<Playlist[]>, YouTubesJsErrors>
const playlists = await client.playlists.getByIds(["ID1", "ID2"]); // Result<Pagination<Playlist[]>, YouTubesJsErrors>
const channelPlaylists = await client.playlists.getByChannelId("CHANNEL_ID"); // Result<Pagination<Playlist[]>, YouTubesJsErrors>
```
17 changes: 11 additions & 6 deletions src/Pagination.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,11 @@ export class Pagination<T> {
* });
* const client = new ApiClient({ oauth });
*
* const playlists = await client.playlists.getMine();
*
* // THIS IS UNSAFE ERROR HANDLING. See the safe error handling in the README.md Introduction.
* const playlists = (await client.playlists.getMine()).throw();
* console.log(playlists.data); // The first page of playlists
* const prevPage = await playlists.prev();
* const prevPage = (await playlists.prev()).throw();
* console.log(prevPage?.data); // The previous page of playlists or null if there is no previous page
* ```
*/
Expand Down Expand Up @@ -120,9 +122,11 @@ export class Pagination<T> {
* });
* const client = new ApiClient({ oauth });
*
* const playlists = await client.playlists.getMine();
*
* // THIS IS UNSAFE ERROR HANDLING. See the safe error handling in the README.md Introduction.
* const playlists = (await client.playlists.getMine()).throw();
* console.log(playlists.data); // The first page of playlists
* const nextPage = await playlists.next();
* const nextPage = (await playlists.next()).throw();
* console.log(nextPage?.data); // The second page of playlists or null if there is no next page
* ```
*/
Expand All @@ -149,8 +153,9 @@ export class Pagination<T> {
* });
* const client = new ApiClient({ oauth });
*
* const playlists = await client.playlists.getMine();
* const allPlaylists = (await playlists.all()).flat();
* // THIS IS UNSAFE ERROR HANDLING. See the safe error handling in the README.md Introduction.
* const playlists = (await client.playlists.getMine()).throw();
* const allPlaylists = (await playlists.all()).throw().flat();
* ```
*/
public async all(): Promise<Result<T[], YouTubesJsErrors>> {
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export type {
} from "./managers/PlaylistManager";

export { ApiClient, ApiClientOptions } from "./ApiClient";
export { YouTubesJsErrors, YouTubeApiError, LikelyBugError } from "./errors";
export {
StaticCredentials,
StaticOAuthProvider,
Expand Down
61 changes: 61 additions & 0 deletions src/managers/PlaylistManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,53 @@ export class PlaylistManager {
return Ok(playlist.data);
}

/**
* Updates a playlist by its ID.
*
* - This operation uses 50 quota units.
* - [If you are submitting an update request, and your request does not specify a value for a property that already has a value, the property's existing value will be deleted.](https://developers.google.com/youtube/v3/docs/playlists/update#request-body)
* - For example, when updating a playlist that has a description set, if you don't specify the `description`, it will be set to an empty string.
* - However, for the `privacy` property, it seems to remain unchanged if not specified.
*
* [YouTube Data API Reference](https://developers.google.com/youtube/v3/docs/playlists/update)
* @param options - Options for updating a playlist.
* @returns - The updated playlist.
*/
public async updateById(
options: UpdatePlaylistOptions,
): Promise<Result<Playlist, YouTubesJsErrors>> {
const {
id,
title,
description,
privacy,
defaultLanguage,
localizations,
} = options;
const rawData = await wrapGaxios(
this.client.playlists.update({
part: this.ALL_PARTS,
requestBody: {
id,
snippet: {
title,
description,
defaultLanguage,
},
status: {
privacyStatus: privacy,
},
localizations,
},
}),
);
if (rawData.isErr()) return Err(rawData.data);
const playlist = Playlist.from(rawData.data, this.logger);
if (playlist.isErr()) return Err(playlist.data);

return Ok(playlist.data);
}

/**
* Deletes a playlist by its ID.
*
Expand Down Expand Up @@ -270,6 +317,20 @@ export interface CreatePlaylistOptions {
localizations?: Record<string, { title: string; description: string }>;
}

export interface UpdatePlaylistOptions {
id: string;

title: string;

description?: string;

privacy?: Privacy;

defaultLanguage?: string;

localizations?: Record<string, { title: string; description: string }>;
}

export interface PlaylistManagerOptions {
oauth: OAuthProviders;
logger: Logger;
Expand Down

0 comments on commit 4351cb7

Please sign in to comment.