Code Monkey home page Code Monkey logo

youtube-studio's Introduction

youtube-studio

CI NPM Downloads NPM Downloads

Unofficial YouTube Studio API. Set of features limited or not provided by official YouTube API

BEWARE: API will change during upcomming releases

Features

  • setting monetisation
  • uploading video (NOT LIMITED - official API's videos.insert charges you 1600 quota units)
  • setting / getting endscreen
  • setting info cards
  • getting video claims
  • getting video details
  • setting video comment options

Installation

$ npm i -SE youtube-studio

Setting monetisation

const { init, setMonetisation } = require('youtube-studio')

await init({ ... }) // read more below (Preparing Authentication)

const result = await setMonetisation({
    encryptedVideoId: 'hHbWF1Bvgf4', // your video ID
    monetizationSettings: {
        newMonetizeWithAds: true // Monetisation: On
    },
    adFormats: { // Type of ads
        newHasOverlayAds: 'ENABLED', // Overlay ads
        newHasProductListingAds: 'ENABLED', // Sponsored cards
        newHasSkippableVideoAds: 'DISABLED', // Skippable video ads
        newHasNonSkippableVideoAds: 'ENABLED', // Non-skippable video ads
        
    },
    adBreaks: { // Location of video ads
        newHasPrerolls: 'DISABLED' // Before video
        newHasMidrollAds: 'DISABLED', // During video
        newHasManualMidrolls: 'DISABLED', // Manual placement (not yet provided)
        newHasPostrolls: 'ENABLED', // After video
        
    },
})

console.log(result)

Uploading video

Official API's videos.insert resource charges you 1600 quota units per single video upload.

const fs = require('fs')
const { init, upload } = require('youtube-studio')

await init({ ... }) // read more below (Preparing Authentication)

const result = await upload({
    channelId: 'UCzQUP1qoWDoEbmsQxvdjxgQ', // your channelId
    stream: fs.createReadStream('./example=video.mp4'), // your video stream

    newTitle: 'new video 1', // optional, your video name
    newDescription: 'Please, subscribe!', // optional, your video description
    newPrivacy: 'PRIVATE', // optional (PRIVATE by default), ('PUBLIC', 'UNLISTED', 'PRIVATE' options available)
    isDraft: false, // optional, video can be a draft (false by default)
})

console.log(result)

Full example with 'progress' feature available in /examples/upload.js

Setting endscreen

const { init, setEndScreen, endScreen } = require('youtube-studio')

await init({ ... }) // read more below (Preparing Authentication)

const videoLengthSec = 1404
const TWENTY_SEC_BEFORE_END_MS = (videoLengthSec - 20) * 1000

const result = await setEndScreen(VIDEO_ID, TWENTY_SEC_BEFORE_END_MS, [
    { ...endScreen.TYPE_RECENT_UPLOAD }, // recent upload in top left position
    { ...endScreen.POSITION_BOTTOM_RIGHT, ...endScreen.TYPE_SUBSCRIBE(CHANNEL_ID) }, // subscribe button
    { ...endScreen.POSITION_TOP_RIGHT,    ...endScreen.TYPE_BEST_FOR_VIEWERS,      ...endScreen.DELAY(500) }, // best for viewers delayed with 0.5 sec
    { ...endScreen.POSITION_BOTTOM_LEFT,  ...endScreen.TYPE_PLAYLIST(PLAYLIST_ID), ...endScreen.DELAY(1000) } // playlist delayed with 1 sec
])
    
console.log(result)

Getting endscreen

const { init, getEndScreen } = require('youtube-studio')

await init({ ... }) // read more below (Preparing Authentication)

const result = await getEndScreen(VIDEO_ID)
    
console.log(result.endscreens[0].elements) // see more in unit tests

Getting video details

const { init, setEndScreen, endScreen } = require('youtube-studio')

await init({ ... }) // read more below (Preparing Authentication)

const result = await getVideo(VIDEO_ID)

const video = result.videos[0]

console.log(video.status) // VIDEO_STATUS_PROCESSED
console.log(video.monetization.adMonetization.effectiveStatus) // VIDEO_MONETIZING_STATUS_MONETIZING_WITH_LIMITED_ADS
console.log(video.lengthSeconds) // '1404'
console.log(video.watchUrl) // '1404'

Setting info cards

const { init, setInfoCards } = require('youtube-studio')

await init({ ... }) // read more below (Preparing Authentication)

const result = await setInfoCards(VIDEO_ID, [{
    playlistId: PLAYLIST_ID,
    teaserStartMs: 15000,
    customMessage: 'Check this one:',
    teaserText: 'If you need more...'
}])

Getting video claims

const { init, getVideoClaims } = require('youtube-studio')

await init({ ... }) // read more below (Preparing Authentication)

const result = await getVideoClaims(CLAIMS_VIDEO_ID)
            
const humanizedClaims = result.receivedClaims.map(claim => {
    const audio = claim.asset.metadata.soundRecording
    const timestamp = claim.matchDetails
    
    return `"${audio.title}", by ${audio.artists.join(', ')} (starting at ${timestamp.longestMatchStartTimeSeconds} sec.)`
})

console.log(humanizedClaims) // ['"Fasl", by Kabul Dreams (starting at 2771 sec.)', ...]

Setting video comment options

Enable all video comments

const { init, setCommentOptions } = require('youtube-studio')

await init({ ... }) // read more below (Preparing Authentication)

const result = await setCommentOptions({
    encryptedVideoId: 'hHbWF1Bvgf4', // your video ID
    commentOptions: {
        newAllowCommentsMode: "ALL_COMMENTS", // or "AUTOMATED_COMMENTS" or "APPROVED_COMMENTS" or "UNKNOWN_COMMENT_ALLOWED_MODE",
        newAllowComments: true, // should be "false" for newAllowCommentsMode="UNKNOWN_COMMENT_ALLOWED_MODE"
        newCanViewRatings: true, // Show how many viewers like and dislike this video
        newDefaultSortOrder: "MDE_COMMENT_SORT_ORDER_LATEST" // or "MDE_COMMENT_SORT_ORDER_TOP"
    }
})

console.log(result)

Disable video comments:

const { init, setCommentOptions } = require('youtube-studio')

await init({ ... }) // read more below (Preparing Authentication)

const result = await setCommentOptions({
    encryptedVideoId: 'hHbWF1Bvgf4',
    commentOptions: {
        newAllowCommentsMode: "UNKNOWN_COMMENT_ALLOWED_MODE",
        newAllowComments: false,
        newCanViewRatings: true, // Show how many viewers like and dislike this video
        newDefaultSortOrder: "MDE_COMMENT_SORT_ORDER_LATEST"
    }
})

console.log(result)

Preparing Authentication

1. Authenticate to studio.youtube.com

It's recommended to do it in a browser's private mode.

2. Open dev tools and copy specific cookie values

IMPORTANT: you need to filter cookies by .youtube.com domain.

Here's a list of required cookies:

  • SID
  • HSID
  • SSID
  • APISID
  • SAPISID
  • LOGIN_INFO (if available)

...like here:

3. Get SESSION_TOKEN

If you plan to use setMonetisation() or upload() or setEndScreen() functions, you need to have SESSION_TOKEN.

IMPORTANT: Keep in mind, that you need to regenerate this value each day.

Use your dev tools to get the value of SESSION_TOKEN (/grst API):

4. Initialize your session:

const { init, getVideo } = require('youtube-studio')

(async () => {
    await init({
        SID,
        HSID,
        SSID,
        APISID,
        SAPISID,
        LOGIN_INFO, // specify, if available in your cookies
        SESSION_TOKEN // this is optional, see point 3. above
    }) // you can authenticate once!

    const video = await getVideo('your video id')
    console.log(video)
}())

youtube-studio's People

Contributors

adamplocieniak avatar adasq avatar cxovrika avatar nieapolitycznie avatar tomasdenhouting avatar tyzesc avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

youtube-studio's Issues

Cookie expiration time?

Hey guys, first of all thanks for this amazing and useful project that provides functionality of some missing endpoints of YouTube API.

I got one question. Overall all cookies have expiration date, for example currently when I'm logged into YouTube Studio, expiration date of my cookies is 2021-04-08T15:46:50.754Z. I want to write a script that will automatically add end screens to all my new videos (probably I'll run it right after I upload a video, or with a cron job), and if I use current cookies, it will work only until expiration date, right? and if yes, can I somehow make it work always with the same initial cookie values? (maybe there's a way to tell studio.youtube.com to update expiration date for cookies?)

I know the expiration time is pretty high, so manually updating cookies that will be used 3-4 times a year should solve the issue, but I'm just still asking maybe you could give me an advice for better solution for this?

Thanks

403 PERMISSION_DENIED even with LOGIN_INFO

Thanks adasq for your comment in the previous issue I opened. Based on that I created a simple node module to try to connect to my YouTube channel but I'm getting this PERMISSION_DENIED error:

{
    "error": {
        "code": 403,
        "message": "The caller does not have permission",
        "errors": [
            {
                "message": "The caller does not have permission",
                "domain": "global",
                "reason": "forbidden"
            }
        ],
        "status": "PERMISSION_DENIED"
    }
}

Here's how I set it up, almost a copy-paste from the examples. I triple-checked the cookie credentials.

To run the script I just ran node index.js directly in the command line.

This is for a google account with 2 channels. I tried using the LOGIN_INFO for each of them, changing the VIDEO_ID and CHANNEL_ID appropriately as well.

Anything I'm doing wrong?

Additional info in case it helps:
Node v14.16.0
Windows 10

Video Rejected

Running the sample code and on the output of 'uploadResult' I am seeing that my upload status is being rejected and the details messaged saying "your video was rejected"

I can upload the same video manually, not too sure why this is occuring

New method to resolve sessionToken

Header:
x-origin: https://studio.youtube.com Authorization: [Replace Your SAPISIDHASH] Content-Type: application/json Cookie: [Replace Your Cookie]

1: POST https://studio.youtube.com/youtubei/v1/security/get_web_reauth_url?alt=json&key=$KEY

Data:
{ "context": { "client": { "clientName": 62, "clientVersion": "1.20220711.03.00", "hl": "en", "gl": "US", }, }, "continueUrl": "https://studio.youtube.com/reauth", "flow": "REAUTH_FLOW_YT_STUDIO_COLD_LOAD", "ivctx": "[Replace Your !!! [ivctx] !!! Required]" }

[encodedReauthProofToken] get the Responses
[sessionRiskCtx] get the Responses

2: POST https://studio.youtube.com/youtubei/v1/ars/grst?alt=json&key=$KEY

Data:
{ "context": { "client": { "clientName": 62, "clientVersion": "1.20220720.01.00", "hl": "en", "gl": "US", }, "request": { "returnLogEntry": true, "internalExperimentFlags": [], "reauthRequestInfo": { "[Replace Your !!! [encodedReauthProofToken] !!! Required]" } }, }, "ctx": "[Replace Your !!! [sessionRiskCtx] !!! Required]" }
[sessionToken] get the Responses

//
**perfect solution,Data information can be filled in completely if necessary **
example:
"user": { "onBehalfOfUser": "[Replace Your UserID]", "delegationContext": { "externalChannelId": "[Replace Your ChannelId@]", "roleType": { "channelRoleType": "CREATOR_CHANNEL_ROLE_TYPE_OWNER" } },

//
sessionToken generally expires in seven days, this scheme can automatically obtain new

Option to set comment options.

Hi,

since official API v3 is missing option to set comment parameters on uploaded videos, I came across this project.
Looking at the few functions available, I tried to add comment support to it based on the setMonetisation function, as it is also using the metadata_update URL, same what a change to the comments options is used.
So I just duplicate the function like this:

async function setComments(commentSettings) {
    let requestBody;

    requestBody = _.cloneDeep(metadata_update_request_payload)

    _.set(requestBody, 'context.user.onBehalfOfUser', config.DELEGATED_SESSION_ID);
    _.set(requestBody, 'context.request.sessionInfo.token', sessionToken);

    requestBody = {
        ...requestBody,
        ...commentSettings
    }

    console.log(requestBody);

    return fetch(`${YT_STUDIO_URL}/youtubei/v1/video_manager/metadata_update?alt=json&key=${config.INNERTUBE_API_KEY}`, {
        method: 'POST',
        headers,
        body: `${JSON.stringify(requestBody)}`
    })
        .then(res => res.json())
}

And used it like this:

const { init, setComments, getVideo } = require('./src/youtube-studio-api');

const SID = '';
const HSID = '';
const SSID = '';
const APISID = '';
const SAPISID = '';
const VIDEO_ID = '';

(async () => {

    await init({ 
        SID,
        HSID,
        SSID,
        APISID,
        SAPISID,
    });

    const result = await setComments({
        encryptedVideoId: VIDEO_ID,
        commentOptions: {
            newAllowComments: false,
            newAllowCommentsMode: "UNKNOWN_COMMENT_ALLOWED_MODE",
            newCanViewRatings: true,
            newDefaultSortOrder: "MDE_COMMENT_SORT_ORDER_TOP"
        },
    });

    console.log(result);
})();

But there seems to be a problem with the request, as I get the following error:

{
  error: {
    code: 400,
    message: 'Request contains an invalid argument.',
    errors: [ [Object] ],
    status: 'INVALID_ARGUMENT'
  }
}

I added a console.log for the requestBody, which looks like this:

{
  encryptedVideoId: '',
  videoReadMask: {},
  commentOptions: {
    newAllowComments: false,
    newAllowCommentsMode: 'UNKNOWN_COMMENT_ALLOWED_MODE',
    newCanViewRatings: true,
    newDefaultSortOrder: 'MDE_COMMENT_SORT_ORDER_TOP'
  },
  selfCertification: {
    newSelfCertificationData: {
      questionnaireAnswers: [Array],
      certificationMethod: 'VIDEO_SELF_CERTIFICATION_METHOD_DEFAULT_NONE',
      questionnaireVersion: 'VIDEO_SELF_CERTIFICATION_QUESTIONNAIRE_VERSION_8'
    }
  },
  context: {
    client: {
      clientName: 62,
      clientVersion: '1.20210104.03.01',
      hl: 'en-GB',
      gl: 'PL',
      experimentsToken: '',
      utcOffsetMinutes: 60
    },
    request: {
      returnLogEntry: true,
      internalExperimentFlags: [],
      sessionInfo: [Object]
    },
    user: {
      onBehalfOfUser: undefined,
      delegationContext: [Object],
      serializedDelegationContext: ''
    },
    clientScreenNonce: ''
  }
}

Any idea what could be wrong with the request?

When to set endscreen?

Hello again @adasq 😄

Since you also have a channel with endscreens, wanted to ask your opinion about the issue I'm currently facing.

The issue is that when I upload a video, on my side (the YouTube API client) I receive response that video has been uploaded (with it's ID, link, and so on), but actually it's in 'processing' state. While YouTube 'processes' your video, you can't set endscreens or cards.
So in my case, once I receive a response that video has been uploaded successfully, I immediately run a script that sets the endscreen and it fails as the 'processing' is not yet finished. The response is something like:

{
    "error": {
        "code": 400,
        "message": "Request contains an invalid argument.",
        "errors": [
            {
                "message": "Request contains an invalid argument.",
                "domain": "global",
                "reason": "badRequest"
            }
        ],
        "status": "INVALID_ARGUMENT"
    }
}

The invalid argument probably means that I passed video_id that was not yet processed. One possible solution is probably polling, to try to set endscreen in ~1min intervals ~20-30 times and exit non-zero in case of no result, but I don't really want to do the polling, so wanted to ask you about how/when do you use the endscreen setter, have you faced the same issue?

P.S. I saw you added upload feature to the project, nice work keep it up! 💪

'could not find "ytcfg". Are you sure SID, HSID, SSID, APISID, SAPISID are correct?'

I'm able to connect to the youtube studio api and call endpoints. But it only works for about 15 minutes. I have to re-log into youtube studio to get new session and cookies, because refreshing the page and adding the new session token still throws the error.

It seems like getMainPage() isn't returning the ytcfg, any ideas on how to fix?

SyntaxError: await is only valid in async function

I created a file called get_video_detail.js in the same path as index.js with the following code as suggested in the README.

When I execute the file using node get_video_detail.js, I am getting the following error.

SyntaxError: await is only valid in async function

near the line await init({

const { init, getVideo } = require('youtube-studio');

await init({
    SID: '',
    HSID: '',
    SSID: '',
    APISID: '',
    SAPISID: '',
});

const video = await getVideo('');
console.log(video);

It would be nice if you can share an example js file.

Cannot read property 'Symbol(Request internals)' of null

const SID= y_cred.SID;
const HSID = y_cred.HSID;
const SSID = y_cred.SSID;
const APISID = y_cred.APISID;
const SAPISID = y_cred.SAPISID;

async () => {
try {
await init({
SID,
HSID,
SSID,
APISID,
SAPISID,
});
} catch (err) {
console.log("error in youtube auth..",err.message)
}
};

const result = await upload({
channelId: environment.CHANNEL_ID, // your channelId
stream:fs.createReadStream("./videos/" + info.videoId + ".mp4"), // your video stream

  newTitle:vData.title, // optional, your video name
  newDescription:vData.description,
  newPrivacy: "PUBLIC", // optional (PRIVATE by default), ('PUBLIC', 'UNLISTED', 'PRIVATE' options available)
  isDraft: false // optional, video can be a draft (false by default)
});

ERROR GOT:
TypeError: Cannot read property 'Symbol(Request internals)' of null
2021-07-09T21:53:25.012471071Z at isRequest (/app/node_modules/node-fetch/lib/index.js:1158:50)
2021-07-09T21:53:25.012478175Z at new Request (/app/node_modules/node-fetch/lib/index.js:1180:8)
2021-07-09T21:53:25.012482824Z at /app/node_modules/node-fetch/lib/index.js:1409:19
2021-07-09T21:53:25.012487102Z at new Promise ()
2021-07-09T21:53:25.013374012Z at fetch (/app/node_modules/node-fetch/lib/index.js:1407:9)
2021-07-09T21:53:25.013379083Z at uploadFile (/app/node_modules/youtube-studio/src/upload/index.js:33:16)
2021-07-09T21:53:25.013383040Z at upload (/app/node_modules/youtube-studio/src/upload/index.js:68:36)
2021-07-09T21:53:25.013387018Z at runMicrotasks ()
2021-07-09T21:53:25.013390955Z at processTicksAndRejections (internal/proces

Help needed. Getting video claims

Hi mate, so one of my test video was blocked and the video claim showed nothing assuming it aims only for audio monetization. Is there a way to generate output if the restriction is not just Copyright Claim but a breach of terms and policies?

Feature request

This is gold, a non-api based youtube "manager". I have to say the new yotube api limitations drive me crazy. Is there any chance to further develop this with an upload a video feature? I wasn't able to find any similar package ( non-api ) with the possibility of a video upload.

how to

hi, after running npm i -SE youtube-studio what to do? where to run other scripts? please can you give me simple tutorials to use this script correctly?

Getting 400 Error while uploading video

{
error: {
code: 400,
message: 'Request contains an invalid argument.',
errors: [ [Object] ],
status: 'INVALID_ARGUMENT'
}
}

I think something might have change in payload from google side

Thumbnail and tags support for video upload

A wonderful module for uploading videos to YouTube, the ability to set a thumbnail and tags for videos is very lacking. It would be great if these features appeared in the next updates. Thanks in advance for a possible implementation.

UnhandledPromiseRejectionWarning:

Love the idea and where this code is headed!

Been playing around with it for the past couple of days and am going a bit bonkers
trying to get it to run with the node command (even with (async () => wrapper) , but can't get around error message:

"UnhandledPromiseRejectionWarning:" et cetera.

Any fixes people can share? Or is s my Node/npm install the culprit?

Initialization problem with Python

Hello there,

I have an app in Python in which I try to do the same things that you are doing here.

My problem is that in initialization I don't always get DELEGATED_SESSION_ID value. It simply doesn't appear in the response of the home page of YouTube studio. This doesn't happen with every account. I have 2 google accounts that I can test with. One that has multiple channels and another that has a single channel. The problem occurs with the second one. I made sure that the requests headers is the same as the one you are using here, but no luck.

I saw in one of the previous opened issues here that it is something related to the LOGIN_INFO cookie, but that didn't solve my problem.

I try to run the same request with the same parameters on node js and it works well. I suspect it is something related maybe to the way HTTP requests are sent, maybe node js is sending requests differently. maybe the default HTTP headers have a role here, I honestly don't know...
Do you know some of the details of how things are done in node js? This may help me to figure out why I get different responses on node js and Python while using the same request.

Any help is appreciated 😄

How to use with/without webpack

Hey, thanks for your work on this. It looks really interesting!

But I have a question. It appear this project isn't compatible with webpack, and that's what I've always used for my javascript applications. I'd be fine with using this without webpack, but I'm not a very advanced frontend programmer, so I'm not very clear on how to do it.

How could I go about running this code in a browser through a standard JavaScript file so that I can use it in my web application and interact with my PHP backend? Any help is appreciated!

Update:
I tried converting the following into a normal front-end JS script using browserify, but it failed due to the vm2 module not being able to detect the version of node. Should I take that to mean that this youtube-studio package is only meant for use on servers running node on that backend and can't be compiled for use on the frontend?

Cannot use setEndScreen anymore. It requires sessionToken

I used setEndScreen over the last year, but a couple of days ago it started to tell me
"Request contains an invalid argument."
When I updated the SID HSID SSID APISID SAPISID
and even tried with LOGIN_INFO and VISITOR_INFO1_LIVE
in different combinations, it didn't change anything.

However, when I set context.request.sessionInfo.token in the body, it works.
But sessionToken expires in a week.

I tried to find a way to refresh session token, and found this issue

But seems like the methods of using [security/get_web_reauth_url] and [ars/grst] are not working anymore.
I get a message "body used already for: https://studio.youtube.com/youtubei/..." for both URLs given.
Looks like it won't work without botGuard.

So my questions are:

Do we require session token to run setEndscreen now?
If yes, then did anyone succeed in updating the session token?

Trim Video Length

Is there an option or could there be added one to trim a video to size by giving it a start and an end time?

I cant get sessionToken

Im trying to get sessionToken on my account, but in esr request I cant see it. What can I do?
image

PERMISSION_DENIED after successful init

Hello again @adasq !

I was playing with the project and checking the features of getting and setting the endscreen of a video. The trouble I'm running into is that I'm able to get information about video endscreen, but I'm unable to set it through JS due to permissions. Have you encountered this kind of problem in your case?

More Details

I first followed steps from Preparing Authentication after a fresh new login. Tested video getter in step 2 and it worked well. Then I manually added endscreen to the video and tested endscreen getter and it also worked well. After this I manually removed endscreen from the video to try to set it from JS.

The problem is that the endscreen setter gives me permission error:

{
    "error": {
        "code": 403,
        "message": "The caller does not have permission",
        "errors": [
            {
                "message": "The caller does not have permission",
                "domain": "global",
                "reason": "forbidden"
            }
        ],
        "status": "PERMISSION_DENIED"
    }
}

Do you have any idea what might be the issue here? Why do the same cookies work with endscreen getter and not endscreen setter. I also noticed that there are some cookies that app does not use, might that be the reason?
cookies

The JS script that I'm using: https://pastebin.com/n8rewA2T
Output of the script:

Connected!
{
    "error": {
        "code": 403,
        "message": "The caller does not have permission",
        "errors": [
            {
                "message": "The caller does not have permission",
                "domain": "global",
                "reason": "forbidden"
            }
        ],
        "status": "PERMISSION_DENIED"
    }
}

Just in case, browser that I used to log in is Google Chrome 85.0.4183.102, OS: Ubuntu 18.04.4 LTS

Thanks in advance for any help or suggestions!

Multi-channel support, broken?

Hey,

Currently with 2 channels on 1 email it doesn't seem to work, even when providing all cookies including LOGIN_INFO, on only 1 of the 2 channels it can upload successfully, and fails on the other one.

Is this a known issue or something wrong with my implementation?

(returns error 400)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.