-3

I am developing an application that is supposed to help a friend of mine better organize his YouTube channels. He has multiple channels on different Google accounts. I'm developing this in Python and I currently don't have too much experience with the YouTube Data API, which I'm planning on using, since it seems like the only option.

The application itself isn't very complicated. The only things it needs to be able to do is upload videos, with a specified title, description and other properties and it should also be possible to write comments on videos. I started a simple application in the Google Developers Console, enabled the YouTube Data API and created an API key and an OAUTH-Client ID.

So far I've managed to post comments on videos, but it seems like every time I run the Python script (currently its just a simple script that posts a single comment) Google wants me to explicitly choose which account I want to use and I have to give permission to the script every time I run it.

Is there a way I can just run the script once and tell Google which account I want to use to post the comment, give all the permissions and Google then remembers that so I don't have to explicitly give permissions every time?

Also how would I be able to then switch accounts and make uploads with that one, because currently I always need to choose one, when the Google client pops up, when running the script.

I've heard you can get an application authorized by Google, would that help with this or is it fine if I just keep my app in test and not in production?

stvar
  • 6,551
  • 2
  • 13
  • 28
roblox99
  • 117
  • 4
  • 3
    where is your code? As I know at first run you have use code which asks for privileges and gives you token which you should save in file. And next time you should load token from file and skip code which asks for privileges. And this can be even shown in Google examples (in GitHub code or in other documentation) – furas Feb 14 '21 at 21:16
  • Welcome to StackOverflow! Please read: [How do I ask a good question?](https://stackoverflow.com/help/how-to-ask) – Pedro Lobito Feb 14 '21 at 21:22
  • 1
    for multiple accounts you will get multiple `tokens` (which you have to keep in file(s) - ie. `pickle`) and every token gives you acccess to only one account. – furas Feb 14 '21 at 21:27
  • 1
    [Any way to use Google Api without every-time authentication?](https://stackoverflow.com/questions/63837906/any-way-to-use-google-api-without-every-time-authentication) – furas Feb 14 '21 at 21:32
  • Please @roblox99 post you question again. They rushed in to close your question right before I was able to finish posting an answer to your API use case. – stvar Feb 14 '21 at 21:38
  • @furas, @Pedro Lobito: You both have rushed in to close a question that deserves an answer (not just glossing about one). The OP's question is legitimate since his use case is about `N` channels to which his app needs to make authorized API calls. Google's docs, its sample code and SO itself does not contain something coherent that would indicate the OP the path to follow. I was right at finishing a post that would have fulfilled documenting such an API use case. – stvar Feb 14 '21 at 21:52
  • @furas: One more thing: the post [Any way to use Google Api without every-time authentication?](https://stackoverflow.com/questions/63837906/any-way-to-use-google-api-without-every-time-authentication) **is not a duplicate** of this one! – stvar Feb 14 '21 at 21:57
  • I do have [a post that indicates the path to follow](https://stackoverflow.com/a/62976250/8327971) solving the OP's use case, but that's relative to PHP -- thus quite different w.r.t. lots of minute details, even though the encompassing logic of that solution is the same as the one corresponding to Python. I also have [a post that documents credentials data persistence to JSON files](https://stackoverflow.com/a/64719550/8327971) (using current Google libraries). Yes, the OP could assemble a solution to his use case, but only after knowing which path to follow. – stvar Feb 14 '21 at 22:11
  • @stvar I reopened question – furas Feb 14 '21 at 22:51
  • @stvar I like to see your answer because I still think this problem is duplicate of problem from my link. If OP uses `N` channels then it needs `N` tokens and keep them in file(s) - it doesn't matter if it will keep it in `JSON` or `pickle`. I think for Google every channel means different user (even all channels belong to one person) and it has to separatelly ask for privileges for every channel and generate token for every channel. – furas Feb 14 '21 at 23:22
  • Please feel free, @roblox99, to ask for further clarifications and/or help. Just post comments under my answer below. – stvar Feb 15 '21 at 09:39
  • Excuse my late answer, but I was quite busy this last week at work. Anyway I did know there were similar questions to mine already answered, but none of those really talked about how to do what I needed for multiple accounts. I already guessed that I probably would need to do the same thing for all accounts, but I just wanted to make sure, which is why I asked this question. – roblox99 Feb 20 '21 at 22:54

1 Answers1

1

If you have N accounts and want to upload videos on each of them, then you'll have to run to successful completion N OAuth 2 authorization/authentication flows.

For each of these N OAuth flows, upon completing each one successfully, you'll have to make persistent the obtained credentials data to a separate file within your computer local storage.

This could well be conceived as an initialization step of your app (although, at any later stage, you may well repeat it for any additional channel that you need your app be aware of). Your code would look like:

# run an OAuth flow; then obtain credentials data
# relative to the channel the app's user had chosen
# during that OAuth flow
from google_auth_oauthlib.flow import InstalledAppFlow
scopes = ['https://www.googleapis.com/auth/youtube']
flow = InstalledAppFlow.from_client_secrets_file(
           client_secret_file, scopes)
cred = flow.run_console()

# build an YouTube service object such that to
# be able to retrieve the ID of the channel that
# the app's user had chosen during the OAuth flow
from googleapiclient.discovery import build
youtube = build('youtube', 'v3', credentials = cred)
response = youtube.channels().list(
    part = 'id',
    mine = True
).execute()
channel_id = response['items'][0]['id']

# save the credentials data to a JSON text file
cred_file = f"/path/to/credentials/data/dir/{channel_id}.json"
with open(cred_file, 'w', encoding = 'UTF-8') as json_file:
    json_file.write(cred.to_json())

Above, client_secret_file is the full path to the file containing your app's client secret JSON file that you've obtained from Google Developers Console.

Subsequently, each time you'll want to upload a video, you'll have to choose from within the app to which channel to upload that video. From the perspective of the logic of your program that would imply the following thing -- say you've chosen the channel of which ID is channel_id: do read in the credentials data file associated to channel_id for to pass its content to your YouTube service object youtube constructed as shown below:

# read in the credentials data associated to
# the channel identified by its ID 'channel_id'
from google.oauth2.credentials import Credentials
cred_file = f"/path/to/credentials/data/dir/{channel_id}.json"
cred = Credentials.from_authorized_user_file(cred_file)

# the access token need be refreshed when
# the previously saved one expired already
from google.auth.transport.requests import Request
assert cred and cred.valid and cred.refresh_token
if cred.expired:
    cred.refresh(Request())
    # save credentials data upon it got refreshed
    with open(cred_file, 'w', encoding = 'UTF-8') as json_file:
        json_file.write(cred.to_json())

# construct an YouTube service object through
# which any API invocations are authorized on
# behalf of the channel with ID 'channel_id'
from googleapiclient.discovery import build
youtube = build('youtube', 'v3', credentials = cred)

Upon running this code, the YouTube service object youtube will be initialized such a way that each an every API endpoint call that is issued through this object will accomplish an authorized request on behalf of the channel identified by channel_id.

An important note: you need to have installed the package Google Authentication Library for Python, google-auth, version >= 1.21.3 (google-auth v1.3.0 introduced Credentials.from_authorized_user_file, v1.8.0 introduced Credentials.to_json and v1.21.3 fixed this latter function w.r.t. its class' expiry member), for the credentials object cred to be saved to and loaded from JSON text files.

Also an important note: the code above is simplified as much as possible. Error conditions are not handled at all. For example, the code above does not handle the error situation when cred_file already exists at the time of writing out a new credentials data file or when cred_file does not exist at the time of reading in credentials data that's supposed to already exist.

stvar
  • 6,551
  • 2
  • 13
  • 28
  • Sorry for my late answer to this, but I was quite busy at work this week. Anyway, this really helped me, thank you a lot. – roblox99 Feb 20 '21 at 22:55
  • Dear stvar, this code really helped me. I am glad you kept pushing to re-open this question – sscalvo Oct 03 '21 at 12:22