youtube_up

Installation

pip install youtube-up

Examples

Upload a video

from youtube_up import AllowCommentsEnum, Metadata, PrivacyEnum, YTUploaderSession

uploader = YTUploaderSession.from_cookies_txt("cookies/cookies.txt")
metadata = Metadata(
    title="Video title",
    description="Video description",
    privacy=PrivacyEnum.PUBLIC,
    made_for_kids=False,
    allow_comments_mode=AllowCommentsEnum.HOLD_ALL,
)
uploader.upload("video.webm", metadata)

Note that for Enum-type parameters we can either pass the Enum itself (as shown above), or the Enum value, or the Enum key, as a string. For example, instead of writing

allow_comments_mode=AllowCommentsEnum.HOLD_ALL

we could instead write allow_comments_mode="HOLD_ALL" or allow_comments_mode="APPROVED_COMMENTS"

Upload multiple videos

from youtube_up import Metadata, YTUploaderSession

uploader = YTUploaderSession.from_cookies_txt("cookies/cookies.txt")
metadata_1 = Metadata(
    title="Video 1",
)
metadata_2 = Metadata(
    title="Video 2",
)
uploader.upload("video1.webm", metadata_1)
uploader.upload("video2.webm", metadata_2)

Upload to a new or existing playlist

from youtube_up import Metadata, YTUploaderSession, Playlist

uploader = YTUploaderSession.from_cookies_txt("cookies/cookies.txt")
metadata = Metadata(
    title="Video 1",
    playlists=[
        Playlist(
            "Songs by me",
            description="Playlist that will only be created if "
            "no playlist exists with the title 'Songs by me'",
            create_if_title_doesnt_exist=True,
            create_if_title_exists=False,
        ),
        Playlist(
            "test playlist",
            description="Playlist that video will be added to "
            "only if it exists already. This description does "
            "nothing.",
            create_if_title_doesnt_exist=False,
            create_if_title_exists=False,
        ),
        Playlist(
            "Album",
            description="Playlist will be created even if there"
            " is already a playlist with the name 'Album'"
            create_if_title_doesnt_exist=True,
            create_if_title_exists=True,
        ),
    ],
)
uploader.upload("video.webm", metadata)

CLI

youtube-up comes with a CLI app for uploading videos. For example, if we wanted to create a public video with the title "Video title", we would execute the following command: youtube-up video video.webm --title="Video title" --cookies_file="cookies/cookies.txt" --privacy="PUBLIC"

The app can also take a JSON file as input. For example, the following JSON file would upload one video to a new or existing playlist called "Music" and one video which is set to premiere on December 25th, 2023 at 5 PM (local time).

[
    {
        "file": "song.webm",
        "metadata": {
            "title": "New song",
            "privacy": "PUBLIC",
            "playlists": [
                {
                    "title": "Music"
                }
            ]
        }
    },
    {
        "file": "premiere.webm",
        "metadata": {
            "title": "Special Announcement",
            "scheduled_upload": "2023-12-25T17:00:00",
            "premiere_countdown_duration": "ONE_MIN",
            "premiere_theme": "BRIGHT"
        }
    }
]

If we wanted the video to premiere at 5 PM GMT, would could have written "2023-12-25T17:00:00+00:00" instead. We then run

youtube-up json metadata.json --cookies_file="cookies/cookies.txt"

to upload these videos.

  1"""
  2# Installation
  3
  4`pip install youtube-up`
  5
  6# Examples
  7
  8## Upload a video
  9```python
 10from youtube_up import AllowCommentsEnum, Metadata, PrivacyEnum, YTUploaderSession
 11
 12uploader = YTUploaderSession.from_cookies_txt("cookies/cookies.txt")
 13metadata = Metadata(
 14    title="Video title",
 15    description="Video description",
 16    privacy=PrivacyEnum.PUBLIC,
 17    made_for_kids=False,
 18    allow_comments_mode=AllowCommentsEnum.HOLD_ALL,
 19)
 20uploader.upload("video.webm", metadata)
 21```
 22Note that for Enum-type parameters we can either pass the Enum itself (as shown above),
 23or the Enum value, or the Enum key, as a string. For example, instead of writing
 24
 25`allow_comments_mode=AllowCommentsEnum.HOLD_ALL`
 26
 27we could instead write `allow_comments_mode="HOLD_ALL"`
 28or `allow_comments_mode="APPROVED_COMMENTS"`
 29
 30## Upload multiple videos
 31```python
 32from youtube_up import Metadata, YTUploaderSession
 33
 34uploader = YTUploaderSession.from_cookies_txt("cookies/cookies.txt")
 35metadata_1 = Metadata(
 36    title="Video 1",
 37)
 38metadata_2 = Metadata(
 39    title="Video 2",
 40)
 41uploader.upload("video1.webm", metadata_1)
 42uploader.upload("video2.webm", metadata_2)
 43```
 44
 45## Upload to a new or existing playlist
 46```python
 47from youtube_up import Metadata, YTUploaderSession, Playlist
 48
 49uploader = YTUploaderSession.from_cookies_txt("cookies/cookies.txt")
 50metadata = Metadata(
 51    title="Video 1",
 52    playlists=[
 53        Playlist(
 54            "Songs by me",
 55            description="Playlist that will only be created if "
 56            "no playlist exists with the title 'Songs by me'",
 57            create_if_title_doesnt_exist=True,
 58            create_if_title_exists=False,
 59        ),
 60        Playlist(
 61            "test playlist",
 62            description="Playlist that video will be added to "
 63            "only if it exists already. This description does "
 64            "nothing.",
 65            create_if_title_doesnt_exist=False,
 66            create_if_title_exists=False,
 67        ),
 68        Playlist(
 69            "Album",
 70            description="Playlist will be created even if there"
 71            " is already a playlist with the name 'Album'"
 72            create_if_title_doesnt_exist=True,
 73            create_if_title_exists=True,
 74        ),
 75    ],
 76)
 77uploader.upload("video.webm", metadata)
 78```
 79
 80## CLI
 81youtube-up comes with a CLI app for uploading videos. For example, if we wanted to
 82create a public video with the title "Video title", we would execute the following command:
 83`youtube-up video video.webm --title="Video title" --cookies_file="cookies/cookies.txt" --privacy="PUBLIC"`
 84
 85The app can also take a JSON file as input. For example, the following JSON file would upload
 86one video to a new or existing playlist called "Music" and one video which is set to premiere
 87on December 25th, 2023 at 5 PM (local time).
 88
 89```json
 90[
 91    {
 92        "file": "song.webm",
 93        "metadata": {
 94            "title": "New song",
 95            "privacy": "PUBLIC",
 96            "playlists": [
 97                {
 98                    "title": "Music"
 99                }
100            ]
101        }
102    },
103    {
104        "file": "premiere.webm",
105        "metadata": {
106            "title": "Special Announcement",
107            "scheduled_upload": "2023-12-25T17:00:00",
108            "premiere_countdown_duration": "ONE_MIN",
109            "premiere_theme": "BRIGHT"
110        }
111    }
112]
113```
114
115If we wanted the video to premiere at 5 PM GMT, would could have written "2023-12-25T17:00:00+00:00"
116instead. We then run
117
118`youtube-up json metadata.json --cookies_file="cookies/cookies.txt"`
119
120to upload these videos.
121"""
122
123
124from .metadata import *
125from .uploader import *
126
127__all__ = uploader.__all__ + metadata.__all__
class YTUploaderSession:
 50class YTUploaderSession:
 51    """
 52    Class for uploading YouTube videos to a single channel
 53    """
 54
 55    _delegated_session_id_regex = re.compile(r'"DELEGATED_SESSION_ID":"([^"]*)"')
 56    _innertube_api_key_regex = re.compile(r'"INNERTUBE_API_KEY":"([^"]*)"')
 57    _session_index_regex = re.compile(r'"SESSION_INDEX":"([^"]*)"')
 58    _channel_id_regex = re.compile(r"https://studio.youtube.com/channel/([^/]*)/*")
 59    _progress_steps = {
 60        "start": 0,
 61        "get_session_data": 10,
 62        "get_upload_url": 20,
 63        "upload_video": 70,
 64        "get_session_token": 80,
 65        "create_video": 90,
 66        "upload_thumbnail": 95,
 67        "finish": 100,
 68    }
 69
 70    _session_token: str
 71    _cookies: FileCookieJar
 72    _session: requests.Session
 73
 74    def __init__(self, cookie_jar: FileCookieJar, webdriver_path: Optional[str] = None, selenium_timeout: float = 60):
 75        """Create YTUploaderSession from generic FileCookieJar
 76
 77        Args:
 78            cookie_jar (FileCookieJar): FileCookieJar. Must have save(), load(),
 79                and set_cookie(http.cookiejar.Cookie) methods
 80            webdriver_path (str, optional): Optional path to geckodriver or chromedriver executable
 81            selenium_timeout (float, optional): Timeout to wait for grst request. Defaults to 60 seconds
 82        """
 83        self._session_token = ""
 84        self._webdriver_path = webdriver_path
 85        self._selenium_timeout = selenium_timeout
 86
 87        # load cookies and init session
 88        self._cookies = cookie_jar
 89        self._cookies.load(ignore_discard=True, ignore_expires=True)
 90        self._session = requests.Session()
 91        for cookie in self._cookies:
 92            if cookie.name == "SESSION_TOKEN":
 93                self._session_token = cookie.value
 94            else:
 95                self._session.cookies.set_cookie(copy.copy(cookie))
 96        self._session.headers = {
 97            "Authorization": f"SAPISIDHASH {self._generateSAPISIDHASH(self._session.cookies['SAPISID'])}",
 98            "x-origin": "https://studio.youtube.com",
 99            "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/119.0",
100        }
101
102    @classmethod
103    def from_cookies_txt(cls, cookies_txt_path: str, webdriver_path: Optional[str] = None, selenium_timeout: float = 60):
104        """Create YTUploaderSession from cookies.txt file
105
106        Args:
107            cookies_txt_path (str): Path to Netscape cookies format file
108            webdriver_path (str, optional): Optional path to geckodriver or chromedriver executable
109            selenium_timeout (float, optional): Timeout to wait for grst request. Defaults to 60 seconds
110        """
111        cj = MozillaCookieJar(cookies_txt_path)
112        return cls(cj, webdriver_path, selenium_timeout)
113
114    def upload(
115        self,
116        file_path: str,
117        metadata: Metadata,
118        progress_callback: Callable[[str, float], None] = lambda step, percent: None,
119    ) -> str:
120        """Upload a video
121
122        Args:
123            file_path (str): Path to video file
124            metadata (Metadata): Metadata of video to set when uploaded
125            progress_callback (Callable[[str, float], None], optional): Optional progress callback.
126                Callback receives what step uploader is on and what the total percentage of the upload
127                progress is (defined by YTUploaderSession._progress_steps).
128        
129        Returns:
130            str: ID of video uploaded
131        """
132        try:
133            metadata.validate()
134        except ValueError as ex:
135            raise YTUploaderException(f"Validation error: {ex}") from ex
136        progress_callback("start", self._progress_steps["start"])
137        data = YTUploaderVideoData()
138        self._get_session_data(data)
139        progress_callback("get_session_data", self._progress_steps["get_session_data"])
140        url = self._get_video_upload_url(data)
141        progress_callback("get_upload_url", self._progress_steps["get_upload_url"])
142        scotty_resource_id = self._upload_file(
143            url, file_path, progress_callback, "get_upload_url", "upload_video"
144        )
145        progress_callback("upload_video", self._progress_steps["upload_video"])
146        try:
147            data.encrypted_video_id = self._create_video(
148                scotty_resource_id, metadata, data
149            )
150        except requests.HTTPError as ex:
151            if ex.response.status_code == 400:
152                # could be bad session token, try to get new one
153                self._get_session_token()
154                progress_callback(
155                    "get_session_token", self._progress_steps["get_session_token"]
156                )
157                data.encrypted_video_id = self._create_video(
158                    scotty_resource_id, metadata, data
159                )
160        progress_callback("create_video", self._progress_steps["create_video"])
161
162        # set thumbnail
163        if metadata.thumbnail is not None:
164            url = self._get_upload_url_thumbnail(data)
165            data.thumbnail_scotty_id = self._upload_file(
166                url,
167                metadata.thumbnail,
168                progress_callback,
169                "create_video",
170                "upload_thumbnail",
171            )
172            data.thumbnail_format = self._get_thumbnail_format(metadata.thumbnail)
173
174        # playlists
175        if metadata.playlists:
176            playlists = self._get_creator_playlists(data)
177            if metadata.playlist_ids is None:
178                metadata.playlist_ids = []
179            for playlist in metadata.playlists:
180                exists = playlist.title in playlists
181                if (playlist.create_if_title_exists and exists) or (
182                    playlist.create_if_title_doesnt_exist and not exists
183                ):
184                    playlist_id = self._create_playlist(playlist, data)
185                    metadata.playlist_ids.append(playlist_id)
186                elif exists:
187                    metadata.playlist_ids.append(playlists[playlist.title])
188        # captions
189        if metadata.captions_files:
190            for caption_file in metadata.captions_files:
191                if caption_file.language is None:
192                    caption_file.language = metadata.audio_language
193                self._update_captions(
194                    caption_file,
195                    data
196                )
197            
198        self._update_metadata(metadata, data)
199        # save cookies
200        for cookie in self._session.cookies:
201            self._cookies.set_cookie(cookie)
202        self._cookies.save()
203        progress_callback("finish", self._progress_steps["finish"])
204        return data.encrypted_video_id
205
206    def has_valid_cookies(self) -> bool:
207        """Check if cookies are valid
208
209        Returns:
210            bool: True if we are able to log in to YouTube with the given cookies
211        """
212        r = self._session.get("https://youtube.com/upload")
213
214        return "studio.youtube.com/channel" in r.url
215
216    def _get_thumbnail_format(self, filename: str) -> ThumbnailFormatEnum:
217        ext = filename.split(".")[-1]
218        if ext in ("jpg", "jpeg", "jfif", "pjpeg", "pjp"):
219            return ThumbnailFormatEnum.JPG
220        if ext in ("png",):
221            return ThumbnailFormatEnum.PNG
222        raise YTUploaderException(
223            f"Unknown format for thumbnail with extension '{ext}'. Only JPEG and PNG allowed"
224        )
225
226    def _get_session_token(self):
227        try:
228            # try firefox
229            options = webdriver.FirefoxOptions()
230            options.add_argument("--headless")
231            if self._webdriver_path:
232                service = FirefoxService(self._webdriver_path)
233                driver = webdriver.Firefox(options=options, service=service)
234            else:
235                driver = webdriver.Firefox(options=options)
236        except Exception:
237            try:
238                # try chrome
239                options = webdriver.ChromeOptions()
240                options.add_argument("--headless=new")
241                if self._webdriver_path:
242                    service = ChromeService(self._webdriver_path)
243                    driver = webdriver.Chrome(options=options, service=service)
244                else:
245                    driver = webdriver.Chrome(options=options)
246            except Exception:
247                raise YTUploaderException(
248                    "Could not launch Firefox or Chrome. Make sure geckodriver or chromedriver is installed"
249                )
250        
251        driver.set_page_load_timeout(self._selenium_timeout)
252
253        driver.get("https://youtube.com")
254
255        for cookie in self._cookies:
256            if cookie.name != "SESSION_TOKEN":
257                driver.add_cookie(cookie.__dict__)
258
259        driver.get("https://youtube.com/upload")
260
261        if "studio.youtube.com/channel" not in driver.current_url:
262            driver.quit()
263            raise YTUploaderException(
264                "Could not log in to YouTube account. Try getting new cookies"
265            )
266
267        r = driver.wait_for_request("studio.youtube.com/youtubei/v1/ars/grst", timeout=self._selenium_timeout)
268        response = r.response
269        r_json = json.loads(
270            decode(response.body, response.headers.get("Content-Encoding"))
271        )
272        self._session_token = r_json["sessionToken"]
273        self._cookies.set_cookie(
274            Cookie(
275                None,
276                "SESSION_TOKEN",
277                self._session_token,
278                None,
279                False,
280                "",
281                False,
282                False,
283                "",
284                False,
285                False,
286                None,
287                False,
288                None,
289                None,
290                {},
291            )
292        )
293        self._cookies.save()
294        driver.quit()
295
296    @staticmethod
297    def _generateUUID() -> str:
298        return str(uuid.uuid4()).upper()
299
300    @staticmethod
301    def _generateSAPISIDHASH(SAPISID) -> str:
302        timestamp = math.floor(time.time())
303        msg = f"{timestamp} {SAPISID} {'https://studio.youtube.com'}"
304        hash = sha1(msg.encode("utf-8")).hexdigest()
305        return f"{timestamp}_{hash}"
306
307    def _get_session_data(self, data: YTUploaderVideoData):
308        r = self._session.get("https://youtube.com/upload")
309
310        if "studio.youtube.com/channel" not in r.url:
311            raise YTUploaderException(
312                "Could not log in to YouTube account. Try getting new cookies"
313            )
314
315        data.channel_id = self._channel_id_regex.match(r.url).group(1)
316        data.innertube_api_key = self._innertube_api_key_regex.search(r.text).group(1)
317        m = self._delegated_session_id_regex.search(r.text)
318        data.delegated_session_id = m and m.group(1)
319        data.authuser = self._session_index_regex.search(r.text).group(1)
320        self._session.headers["X-Goog-AuthUser"] = data.authuser
321
322    def _get_upload_url(self, api_url: str, authuser: str, data: dict) -> str:
323        params = {"authuser": authuser}
324        headers = {
325            "x-goog-upload-command": "start",
326            "x-goog-upload-protocol": "resumable",
327        }
328        r = self._session.post(
329            api_url,
330            headers=headers,
331            params=params,
332            json=data,
333        )
334        r.raise_for_status()
335        upload_url = r.headers["x-goog-upload-url"]
336        return upload_url
337
338    def _get_video_upload_url(self, data: YTUploaderVideoData) -> str:
339        data.front_end_upload_id = f"innertube_studio:{self._generateUUID()}:0"
340        return self._get_upload_url(
341            "https://upload.youtube.com/upload/studio",
342            data.authuser,
343            {"frontendUploadId": data.front_end_upload_id},
344        )
345
346    def _get_upload_url_thumbnail(self, data: YTUploaderVideoData) -> str:
347        return self._get_upload_url(
348            "https://upload.youtube.com/upload/studiothumbnail", data.authuser, {}
349        )
350
351    def _get_creator_playlists(self, data: YTUploaderVideoData) -> Dict[str, str]:
352        params = {"key": data.innertube_api_key, "alt": "json"}
353        data = APIRequestListPlaylists.from_session_data(
354            data.channel_id,
355            self._session_token,
356            data.delegated_session_id
357        ).to_dict()
358        r = self._session.post(
359            "https://studio.youtube.com/youtubei/v1/creator/list_creator_playlists",
360            params=params,
361            json=data,
362        )
363        r.raise_for_status()
364        return {
365            playlist["title"]: playlist["playlistId"]
366            for playlist in r.json().get("playlists", [])
367        }
368
369    def _create_playlist(
370        self,
371        playlist: Playlist,
372        data: YTUploaderVideoData,
373    ) -> str:
374        params = {"key": data.innertube_api_key, "alt": "json"}
375        data = APIRequestCreatePlaylist.from_session_data(
376            data.channel_id, self._session_token, data.delegated_session_id, playlist
377        ).to_dict()
378        r = self._session.post(
379            "https://studio.youtube.com/youtubei/v1/playlist/create",
380            params=params,
381            json=data,
382        )
383        r.raise_for_status()
384        return r.json()["playlistId"]
385
386    def _update_captions(
387        self,
388        caption_file: CaptionsFile,
389        data: YTUploaderVideoData,
390    ):
391        params = {"key": data.innertube_api_key, "alt": "json"}
392        with open(caption_file.path, "rb") as f:
393            captions_b64 = "data:application/octet-stream;base64," + base64.b64encode(f.read()).decode("utf-8")
394        timestamp = str(time.time_ns())
395        data = APIRequestUpdateCaptions.from_session_data(
396            data.channel_id,
397            self._session_token,
398            data.delegated_session_id,
399            data.encrypted_video_id,
400            caption_file.path,
401            captions_b64,
402            caption_file.language,
403            timestamp
404        ).to_dict()
405        r = self._session.post(
406            "https://studio.youtube.com/youtubei/v1/globalization/update_captions",
407            params=params,
408            json=data,
409        )
410        r.raise_for_status()
411
412    def _upload_file(
413        self,
414        upload_url: str,
415        file_path: str,
416        progress_callback: Callable[[str, float], None],
417        prev_progress_step: str,
418        cur_progress_step: str,
419    ):
420        headers = {
421            "x-goog-upload-command": "upload, finalize",
422            "x-goog-upload-offset": "0",
423        }
424
425        with open(file_path, "rb") as f:
426            f.seek(0, os.SEEK_END)
427            size = f.tell()
428            f.seek(0)
429            bytes_sent = 0
430
431            def upload_callback(bytes: int):
432                nonlocal bytes_sent
433                bytes_sent += bytes
434                start_prog = self._progress_steps[prev_progress_step]
435                end_prog = self._progress_steps[cur_progress_step]
436                cur_prog = start_prog + (end_prog - start_prog) * (bytes_sent / size)
437                cur_prog = round(cur_prog, 1)
438                progress_callback(cur_progress_step, cur_prog)
439
440            wrapped_file = CallbackIOWrapper(upload_callback, f)
441            r = self._session.post(upload_url, headers=headers, data=wrapped_file)
442
443        r.raise_for_status()
444        return r.json()["scottyResourceId"]
445
446    def _create_video(
447        self, scotty_resource_id: str, metadata: Metadata, data: YTUploaderVideoData
448    ) -> str:
449        params = {"key": data.innertube_api_key, "alt": "json"}
450        data = APIRequestCreateVideo.from_session_data(
451            data.channel_id,
452            self._session_token,
453            data.delegated_session_id,
454            data.front_end_upload_id,
455            metadata,
456            scotty_resource_id,
457        ).to_dict()
458        r = self._session.post(
459            "https://studio.youtube.com/youtubei/v1/upload/createvideo",
460            params=params,
461            json=data,
462        )
463        r.raise_for_status()
464        r = r.json()
465        if "videoId" not in r:
466            raise YTUploaderException(
467                f"Could not upload. Daily limit may have been reached. Response: {r}"
468            )
469        return r["videoId"]
470
471    def _update_metadata(self, metadata: Metadata, data: YTUploaderVideoData):
472        params = {"key": data.innertube_api_key, "alt": "json"}
473        data = APIRequestUpdateMetadata.from_session_data(
474            data.channel_id,
475            self._session_token,
476            data.delegated_session_id,
477            data.encrypted_video_id,
478            metadata,
479            data.thumbnail_scotty_id,
480            data.thumbnail_format,
481        ).to_dict()
482        r = self._session.post(
483            "https://studio.youtube.com/youtubei/v1/video_manager/metadata_update",
484            params=params,
485            json=data,
486        )
487        r.raise_for_status()

Class for uploading YouTube videos to a single channel

YTUploaderSession( cookie_jar: http.cookiejar.FileCookieJar, webdriver_path: Optional[str] = None, selenium_timeout: float = 60)
 74    def __init__(self, cookie_jar: FileCookieJar, webdriver_path: Optional[str] = None, selenium_timeout: float = 60):
 75        """Create YTUploaderSession from generic FileCookieJar
 76
 77        Args:
 78            cookie_jar (FileCookieJar): FileCookieJar. Must have save(), load(),
 79                and set_cookie(http.cookiejar.Cookie) methods
 80            webdriver_path (str, optional): Optional path to geckodriver or chromedriver executable
 81            selenium_timeout (float, optional): Timeout to wait for grst request. Defaults to 60 seconds
 82        """
 83        self._session_token = ""
 84        self._webdriver_path = webdriver_path
 85        self._selenium_timeout = selenium_timeout
 86
 87        # load cookies and init session
 88        self._cookies = cookie_jar
 89        self._cookies.load(ignore_discard=True, ignore_expires=True)
 90        self._session = requests.Session()
 91        for cookie in self._cookies:
 92            if cookie.name == "SESSION_TOKEN":
 93                self._session_token = cookie.value
 94            else:
 95                self._session.cookies.set_cookie(copy.copy(cookie))
 96        self._session.headers = {
 97            "Authorization": f"SAPISIDHASH {self._generateSAPISIDHASH(self._session.cookies['SAPISID'])}",
 98            "x-origin": "https://studio.youtube.com",
 99            "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/119.0",
100        }

Create YTUploaderSession from generic FileCookieJar

Arguments:
  • cookie_jar (FileCookieJar): FileCookieJar. Must have save(), load(), and set_cookie(http.cookiejar.Cookie) methods
  • webdriver_path (str, optional): Optional path to geckodriver or chromedriver executable
  • selenium_timeout (float, optional): Timeout to wait for grst request. Defaults to 60 seconds
@classmethod
def from_cookies_txt( cls, cookies_txt_path: str, webdriver_path: Optional[str] = None, selenium_timeout: float = 60):
102    @classmethod
103    def from_cookies_txt(cls, cookies_txt_path: str, webdriver_path: Optional[str] = None, selenium_timeout: float = 60):
104        """Create YTUploaderSession from cookies.txt file
105
106        Args:
107            cookies_txt_path (str): Path to Netscape cookies format file
108            webdriver_path (str, optional): Optional path to geckodriver or chromedriver executable
109            selenium_timeout (float, optional): Timeout to wait for grst request. Defaults to 60 seconds
110        """
111        cj = MozillaCookieJar(cookies_txt_path)
112        return cls(cj, webdriver_path, selenium_timeout)

Create YTUploaderSession from cookies.txt file

Arguments:
  • cookies_txt_path (str): Path to Netscape cookies format file
  • webdriver_path (str, optional): Optional path to geckodriver or chromedriver executable
  • selenium_timeout (float, optional): Timeout to wait for grst request. Defaults to 60 seconds
def upload( self, file_path: str, metadata: Metadata, progress_callback: Callable[[str, float], NoneType] = <function YTUploaderSession.<lambda>>) -> str:
114    def upload(
115        self,
116        file_path: str,
117        metadata: Metadata,
118        progress_callback: Callable[[str, float], None] = lambda step, percent: None,
119    ) -> str:
120        """Upload a video
121
122        Args:
123            file_path (str): Path to video file
124            metadata (Metadata): Metadata of video to set when uploaded
125            progress_callback (Callable[[str, float], None], optional): Optional progress callback.
126                Callback receives what step uploader is on and what the total percentage of the upload
127                progress is (defined by YTUploaderSession._progress_steps).
128        
129        Returns:
130            str: ID of video uploaded
131        """
132        try:
133            metadata.validate()
134        except ValueError as ex:
135            raise YTUploaderException(f"Validation error: {ex}") from ex
136        progress_callback("start", self._progress_steps["start"])
137        data = YTUploaderVideoData()
138        self._get_session_data(data)
139        progress_callback("get_session_data", self._progress_steps["get_session_data"])
140        url = self._get_video_upload_url(data)
141        progress_callback("get_upload_url", self._progress_steps["get_upload_url"])
142        scotty_resource_id = self._upload_file(
143            url, file_path, progress_callback, "get_upload_url", "upload_video"
144        )
145        progress_callback("upload_video", self._progress_steps["upload_video"])
146        try:
147            data.encrypted_video_id = self._create_video(
148                scotty_resource_id, metadata, data
149            )
150        except requests.HTTPError as ex:
151            if ex.response.status_code == 400:
152                # could be bad session token, try to get new one
153                self._get_session_token()
154                progress_callback(
155                    "get_session_token", self._progress_steps["get_session_token"]
156                )
157                data.encrypted_video_id = self._create_video(
158                    scotty_resource_id, metadata, data
159                )
160        progress_callback("create_video", self._progress_steps["create_video"])
161
162        # set thumbnail
163        if metadata.thumbnail is not None:
164            url = self._get_upload_url_thumbnail(data)
165            data.thumbnail_scotty_id = self._upload_file(
166                url,
167                metadata.thumbnail,
168                progress_callback,
169                "create_video",
170                "upload_thumbnail",
171            )
172            data.thumbnail_format = self._get_thumbnail_format(metadata.thumbnail)
173
174        # playlists
175        if metadata.playlists:
176            playlists = self._get_creator_playlists(data)
177            if metadata.playlist_ids is None:
178                metadata.playlist_ids = []
179            for playlist in metadata.playlists:
180                exists = playlist.title in playlists
181                if (playlist.create_if_title_exists and exists) or (
182                    playlist.create_if_title_doesnt_exist and not exists
183                ):
184                    playlist_id = self._create_playlist(playlist, data)
185                    metadata.playlist_ids.append(playlist_id)
186                elif exists:
187                    metadata.playlist_ids.append(playlists[playlist.title])
188        # captions
189        if metadata.captions_files:
190            for caption_file in metadata.captions_files:
191                if caption_file.language is None:
192                    caption_file.language = metadata.audio_language
193                self._update_captions(
194                    caption_file,
195                    data
196                )
197            
198        self._update_metadata(metadata, data)
199        # save cookies
200        for cookie in self._session.cookies:
201            self._cookies.set_cookie(cookie)
202        self._cookies.save()
203        progress_callback("finish", self._progress_steps["finish"])
204        return data.encrypted_video_id

Upload a video

Arguments:
  • file_path (str): Path to video file
  • metadata (Metadata): Metadata of video to set when uploaded
  • progress_callback (Callable[[str, float], None], optional): Optional progress callback. Callback receives what step uploader is on and what the total percentage of the upload progress is (defined by YTUploaderSession._progress_steps).
Returns:

str: ID of video uploaded

def has_valid_cookies(self) -> bool:
206    def has_valid_cookies(self) -> bool:
207        """Check if cookies are valid
208
209        Returns:
210            bool: True if we are able to log in to YouTube with the given cookies
211        """
212        r = self._session.get("https://youtube.com/upload")
213
214        return "studio.youtube.com/channel" in r.url

Check if cookies are valid

Returns:

bool: True if we are able to log in to YouTube with the given cookies

class YTUploaderException(builtins.Exception):
34class YTUploaderException(Exception):
35    """YouTube uploader exception"""

YouTube uploader exception

Inherited Members
builtins.Exception
Exception
builtins.BaseException
with_traceback
args
@dataclass_json
@dataclass
class Metadata:
383@dataclass_json
384@dataclass
385class Metadata:
386    """Metadata of video to upload"""
387
388    title: str
389    """Title. Max length 100. Cannot contain < or > characters"""
390
391    description: str = ""
392    """Description. Max length 5000. Cannot contain < or > characters"""
393
394    privacy: PrivacyEnum = PrivacyEnum.PRIVATE
395    """Privacy. Possible values: PUBLIC, UNLISTED, PRIVATE"""
396
397    made_for_kids: bool = False
398    """Made for kids. If true comments will be disabled"""
399
400    tags: List[str] = ()
401    """List of tags"""
402
403    # optional metadata for update_metadata
404    scheduled_upload: Optional[datetime.datetime] = field(
405        default=None,
406        metadata=config(
407            decoder=lambda x: datetime.datetime.fromisoformat(x) if x is not None else None,
408            encoder=lambda x: datetime.datetime.isoformat(x) if x is not None else None,
409            mm_field=mm_field.DateTime("iso", allow_none=True)
410        ),
411    )
412    """
413    Date to make upload public. If set, video will be set to private until the date, unless video
414    is a premiere in which case it will be set to public. Video will not be a premiere unless both
415    premiere_countdown_duration and premiere_theme are set
416    """
417
418    premiere_countdown_duration: Optional[PremiereDurationEnum] = None
419    """Duration of premiere countdown in seconds. Possible values: 60, 120, 180, 240, 300"""
420
421    premiere_theme: Optional[PremiereThemeEnum] = None
422    """
423    Theme of premiere countdown. Possible values: CLASSIC, ALTERNATIVE, AMBIENT, BRIGHT, CALM,
424    CINEMATIC, CONTEMPORARY, DRAMATIC, FUNKY, GENTLE, HAPPY, INSPIRATIONAL, KIDS, SCI_FI, SPORTS
425    """
426
427    playlist_ids: Optional[List[str]] = None
428    """List of existing playlist IDs to add video to"""
429
430    playlists: Optional[List[Playlist]] = None
431    """List of playlists to create and/or add video to"""
432
433    thumbnail: Optional[str] = None
434    """Path to thumbnail file to upload"""
435
436    publish_to_feed: Optional[bool] = None
437    """Whether to notify subscribers"""
438
439    category: Optional[CategoryEnum] = None
440    """Category. Category-specific metadata is not supported yet. Possible values: FILM_ANIMATION,
441    AUTOS_VEHICLES, MUSIC, PETS_ANIMALS, SPORTS, TRAVEL_EVENTS, GAMING, PEOPLE_BLOGS, COMEDY,
442    ENTERTAINMENT, NEWS_POLITICS, HOWTO_STYLE, EDUCATION, SCIENCE_TECH, NONPROFITS_ACTIVISM"""
443
444    auto_chapter: Optional[bool] = None
445    """Whether to use automatic video chapters"""
446
447    auto_places: Optional[bool] = None
448    """Whether to use automatic places"""
449
450    auto_concepts: Optional[bool] = None
451    """Whether to use automatic concepts"""
452
453    has_product_placement: Optional[bool] = None
454    """Whether video has product placement"""
455
456    show_product_placement_overlay: Optional[bool] = None
457    """Whether to show product placement overlay"""
458
459    recorded_date: Optional[datetime.date] = field(
460        default=None,
461        metadata=config(
462            decoder=lambda x: datetime.date.fromisoformat(x) if x is not None else None,
463            encoder=lambda x: datetime.date.isoformat(x) if x is not None else None,
464            mm_field=mm_field.Date("iso", allow_none=True)
465        ),
466    )
467    """Day, month, and year that video was recorded"""
468
469    restricted_to_over_18: Optional[bool] = None
470    """Whether video is age restricted"""
471
472    audio_language: Optional[LanguageEnum] = None
473    """Language of audio"""
474    
475    captions_files: Optional[List[CaptionsFile]] = None
476    """Path to captions files (.srt)"""
477
478    license: Optional[LicenseEnum] = None
479    """License. Possible values: STANDARD, CREATIVE_COMMONS"""
480
481    allow_comments: Optional[bool] = None
482    """Whether to allow comments"""
483
484    allow_comments_mode: Optional[AllowCommentsEnum] = None
485    """Comment filtering mode. Possible values: ALL_COMMENTS, HOLD_INAPPROPRIATE,
486    HOLD_INAPPROPRIATE_STRICT, HOLD_ALL"""
487
488    can_view_ratings: Optional[bool] = None
489    """Whether video likes/dislikes can be seen"""
490
491    comments_sort_order: Optional[CommentsSortOrderEnum] = None
492    """Default comment sort order. Possible values: LATEST, TOP"""
493
494    allow_embedding: Optional[bool] = None
495    """Whether to allow embedding on 3rd party sites"""
496    
497    def validate(self):
498        """Raises error if metadata is invalid"""
499        if self.premiere_countdown_duration is not None or self.premiere_theme is not None:
500            if None in (self.premiere_countdown_duration, self.premiere_theme, self.scheduled_upload):
501                raise ValueError(
502                    "If trying to upload a premiere, premiere_countdown_duration, "
503                    "premiere_theme, and scheduled_upload must be set"
504                )
505        
506        if self.captions_files is not None:
507            for caption_file in self.captions_files:
508                if caption_file.language is None and self.audio_language is None:
509                    raise ValueError(
510                        "Must either specify captions file language or audio_language"
511                    )
512        
513        if self.restricted_to_over_18 and self.made_for_kids:
514            raise ValueError(
515                "Video cannot be made for kids and also restricted to over 18"
516            )
517        
518        if len(self.title) > 100:
519            raise ValueError("Title must be at most 100 characters long")
520        
521        if len(self.description) > 5000:
522            raise ValueError("Description must be at most 5000 characters long")
523        
524        if any(c in s for c in "<>" for s in (self.title, self.description)):
525            raise ValueError("Title and description cannot contain angled brackets")
526        
527        
528        errors = self.schema().validate(self.to_dict())
529        if errors:
530            raise ValueError(f"{errors}")

Metadata of video to upload

Metadata( title: str, description: str = '', privacy: PrivacyEnum = <PrivacyEnum.PRIVATE: 'PRIVATE'>, made_for_kids: bool = False, tags: List[str] = (), scheduled_upload: Optional[datetime.datetime] = None, premiere_countdown_duration: Optional[PremiereDurationEnum] = None, premiere_theme: Optional[PremiereThemeEnum] = None, playlist_ids: Optional[List[str]] = None, playlists: Optional[List[Playlist]] = None, thumbnail: Optional[str] = None, publish_to_feed: Optional[bool] = None, category: Optional[CategoryEnum] = None, auto_chapter: Optional[bool] = None, auto_places: Optional[bool] = None, auto_concepts: Optional[bool] = None, has_product_placement: Optional[bool] = None, show_product_placement_overlay: Optional[bool] = None, recorded_date: Optional[datetime.date] = None, restricted_to_over_18: Optional[bool] = None, audio_language: Optional[LanguageEnum] = None, captions_files: Optional[List[CaptionsFile]] = None, license: Optional[LicenseEnum] = None, allow_comments: Optional[bool] = None, allow_comments_mode: Optional[AllowCommentsEnum] = None, can_view_ratings: Optional[bool] = None, comments_sort_order: Optional[CommentsSortOrderEnum] = None, allow_embedding: Optional[bool] = None)
title: str

Title. Max length 100. Cannot contain < or > characters

description: str = ''

Description. Max length 5000. Cannot contain < or > characters

privacy: PrivacyEnum = <PrivacyEnum.PRIVATE: 'PRIVATE'>

Privacy. Possible values: PUBLIC, UNLISTED, PRIVATE

made_for_kids: bool = False

Made for kids. If true comments will be disabled

tags: List[str] = ()

List of tags

scheduled_upload: Optional[datetime.datetime] = None

Date to make upload public. If set, video will be set to private until the date, unless video is a premiere in which case it will be set to public. Video will not be a premiere unless both premiere_countdown_duration and premiere_theme are set

premiere_countdown_duration: Optional[PremiereDurationEnum] = None

Duration of premiere countdown in seconds. Possible values: 60, 120, 180, 240, 300

premiere_theme: Optional[PremiereThemeEnum] = None

Theme of premiere countdown. Possible values: CLASSIC, ALTERNATIVE, AMBIENT, BRIGHT, CALM, CINEMATIC, CONTEMPORARY, DRAMATIC, FUNKY, GENTLE, HAPPY, INSPIRATIONAL, KIDS, SCI_FI, SPORTS

playlist_ids: Optional[List[str]] = None

List of existing playlist IDs to add video to

playlists: Optional[List[Playlist]] = None

List of playlists to create and/or add video to

thumbnail: Optional[str] = None

Path to thumbnail file to upload

publish_to_feed: Optional[bool] = None

Whether to notify subscribers

category: Optional[CategoryEnum] = None

Category. Category-specific metadata is not supported yet. Possible values: FILM_ANIMATION, AUTOS_VEHICLES, MUSIC, PETS_ANIMALS, SPORTS, TRAVEL_EVENTS, GAMING, PEOPLE_BLOGS, COMEDY, ENTERTAINMENT, NEWS_POLITICS, HOWTO_STYLE, EDUCATION, SCIENCE_TECH, NONPROFITS_ACTIVISM

auto_chapter: Optional[bool] = None

Whether to use automatic video chapters

auto_places: Optional[bool] = None

Whether to use automatic places

auto_concepts: Optional[bool] = None

Whether to use automatic concepts

has_product_placement: Optional[bool] = None

Whether video has product placement

show_product_placement_overlay: Optional[bool] = None

Whether to show product placement overlay

recorded_date: Optional[datetime.date] = None

Day, month, and year that video was recorded

restricted_to_over_18: Optional[bool] = None

Whether video is age restricted

audio_language: Optional[LanguageEnum] = None

Language of audio

captions_files: Optional[List[CaptionsFile]] = None

Path to captions files (.srt)

license: Optional[LicenseEnum] = None

License. Possible values: STANDARD, CREATIVE_COMMONS

allow_comments: Optional[bool] = None

Whether to allow comments

allow_comments_mode: Optional[AllowCommentsEnum] = None

Comment filtering mode. Possible values: ALL_COMMENTS, HOLD_INAPPROPRIATE, HOLD_INAPPROPRIATE_STRICT, HOLD_ALL

can_view_ratings: Optional[bool] = None

Whether video likes/dislikes can be seen

comments_sort_order: Optional[CommentsSortOrderEnum] = None

Default comment sort order. Possible values: LATEST, TOP

allow_embedding: Optional[bool] = None

Whether to allow embedding on 3rd party sites

def validate(self):
497    def validate(self):
498        """Raises error if metadata is invalid"""
499        if self.premiere_countdown_duration is not None or self.premiere_theme is not None:
500            if None in (self.premiere_countdown_duration, self.premiere_theme, self.scheduled_upload):
501                raise ValueError(
502                    "If trying to upload a premiere, premiere_countdown_duration, "
503                    "premiere_theme, and scheduled_upload must be set"
504                )
505        
506        if self.captions_files is not None:
507            for caption_file in self.captions_files:
508                if caption_file.language is None and self.audio_language is None:
509                    raise ValueError(
510                        "Must either specify captions file language or audio_language"
511                    )
512        
513        if self.restricted_to_over_18 and self.made_for_kids:
514            raise ValueError(
515                "Video cannot be made for kids and also restricted to over 18"
516            )
517        
518        if len(self.title) > 100:
519            raise ValueError("Title must be at most 100 characters long")
520        
521        if len(self.description) > 5000:
522            raise ValueError("Description must be at most 5000 characters long")
523        
524        if any(c in s for c in "<>" for s in (self.title, self.description)):
525            raise ValueError("Title and description cannot contain angled brackets")
526        
527        
528        errors = self.schema().validate(self.to_dict())
529        if errors:
530            raise ValueError(f"{errors}")

Raises error if metadata is invalid

def to_json( self, *, skipkeys: bool = False, ensure_ascii: bool = True, check_circular: bool = True, allow_nan: bool = True, indent: Union[str, int, NoneType] = None, separators: Optional[Tuple[str, str]] = None, default: Optional[Callable] = None, sort_keys: bool = False, **kw) -> str:
27    def to_json(self,
28                *,
29                skipkeys: bool = False,
30                ensure_ascii: bool = True,
31                check_circular: bool = True,
32                allow_nan: bool = True,
33                indent: Optional[Union[int, str]] = None,
34                separators: Optional[Tuple[str, str]] = None,
35                default: Optional[Callable] = None,
36                sort_keys: bool = False,
37                **kw) -> str:
38        return json.dumps(self.to_dict(encode_json=False),
39                          cls=_ExtendedEncoder,
40                          skipkeys=skipkeys,
41                          ensure_ascii=ensure_ascii,
42                          check_circular=check_circular,
43                          allow_nan=allow_nan,
44                          indent=indent,
45                          separators=separators,
46                          default=default,
47                          sort_keys=sort_keys,
48                          **kw)
@classmethod
def from_json( cls: Type[~A], s: Union[str, bytes, bytearray], *, parse_float=None, parse_int=None, parse_constant=None, infer_missing=False, **kw) -> ~A:
50    @classmethod
51    def from_json(cls: Type[A],
52                  s: JsonData,
53                  *,
54                  parse_float=None,
55                  parse_int=None,
56                  parse_constant=None,
57                  infer_missing=False,
58                  **kw) -> A:
59        kvs = json.loads(s,
60                         parse_float=parse_float,
61                         parse_int=parse_int,
62                         parse_constant=parse_constant,
63                         **kw)
64        return cls.from_dict(kvs, infer_missing=infer_missing)
def to_dict( self, encode_json=False) -> Dict[str, Union[dict, list, str, int, float, bool, NoneType]]:
73    def to_dict(self, encode_json=False) -> Dict[str, Json]:
74        return _asdict(self, encode_json=encode_json)
@classmethod
def from_dict( cls: Type[~A], kvs: Union[dict, list, str, int, float, bool, NoneType], *, infer_missing=False) -> ~A:
66    @classmethod
67    def from_dict(cls: Type[A],
68                  kvs: Json,
69                  *,
70                  infer_missing=False) -> A:
71        return _decode_dataclass(cls, kvs, infer_missing)
@classmethod
def schema( cls: Type[~A], *, infer_missing: bool = False, only=None, exclude=(), many: bool = False, context=None, load_only=(), dump_only=(), partial: bool = False, unknown=None) -> dataclasses_json.mm.SchemaF[~A]:
 76    @classmethod
 77    def schema(cls: Type[A],
 78               *,
 79               infer_missing: bool = False,
 80               only=None,
 81               exclude=(),
 82               many: bool = False,
 83               context=None,
 84               load_only=(),
 85               dump_only=(),
 86               partial: bool = False,
 87               unknown=None) -> "SchemaType[A]":
 88        Schema = build_schema(cls, DataClassJsonMixin, infer_missing, partial)
 89
 90        if unknown is None:
 91            undefined_parameter_action = _undefined_parameter_action_safe(cls)
 92            if undefined_parameter_action is not None:
 93                # We can just make use of the same-named mm keywords
 94                unknown = undefined_parameter_action.name.lower()
 95
 96        return Schema(only=only,
 97                      exclude=exclude,
 98                      many=many,
 99                      context=context,
100                      load_only=load_only,
101                      dump_only=dump_only,
102                      partial=partial,
103                      unknown=unknown)
@dataclass_json
@dataclass
class Playlist:
349@dataclass_json
350@dataclass
351class Playlist:
352    """Metadata of playlist to create and/or add video to"""
353
354    title: str
355    """Title. Max length 150"""
356
357    description: str = ""
358    """Description. Max length 5000"""
359
360    privacy: PrivacyEnum = PrivacyEnum.PUBLIC
361    """Privacy. Possible values: PUBLIC, UNLISTED, PRIVATE"""
362
363    create_if_title_exists: bool = False
364    """Whether to create playlist if a playlist with the same
365    title already exists on the channel"""
366
367    create_if_title_doesnt_exist: bool = True
368    """Whether to create playlist if there is no playlist with the same title"""

Metadata of playlist to create and/or add video to

Playlist( title: str, description: str = '', privacy: PrivacyEnum = <PrivacyEnum.PUBLIC: 'PUBLIC'>, create_if_title_exists: bool = False, create_if_title_doesnt_exist: bool = True)
title: str

Title. Max length 150

description: str = ''

Description. Max length 5000

privacy: PrivacyEnum = <PrivacyEnum.PUBLIC: 'PUBLIC'>

Privacy. Possible values: PUBLIC, UNLISTED, PRIVATE

create_if_title_exists: bool = False

Whether to create playlist if a playlist with the same title already exists on the channel

create_if_title_doesnt_exist: bool = True

Whether to create playlist if there is no playlist with the same title

def to_json( self, *, skipkeys: bool = False, ensure_ascii: bool = True, check_circular: bool = True, allow_nan: bool = True, indent: Union[str, int, NoneType] = None, separators: Optional[Tuple[str, str]] = None, default: Optional[Callable] = None, sort_keys: bool = False, **kw) -> str:
27    def to_json(self,
28                *,
29                skipkeys: bool = False,
30                ensure_ascii: bool = True,
31                check_circular: bool = True,
32                allow_nan: bool = True,
33                indent: Optional[Union[int, str]] = None,
34                separators: Optional[Tuple[str, str]] = None,
35                default: Optional[Callable] = None,
36                sort_keys: bool = False,
37                **kw) -> str:
38        return json.dumps(self.to_dict(encode_json=False),
39                          cls=_ExtendedEncoder,
40                          skipkeys=skipkeys,
41                          ensure_ascii=ensure_ascii,
42                          check_circular=check_circular,
43                          allow_nan=allow_nan,
44                          indent=indent,
45                          separators=separators,
46                          default=default,
47                          sort_keys=sort_keys,
48                          **kw)
@classmethod
def from_json( cls: Type[~A], s: Union[str, bytes, bytearray], *, parse_float=None, parse_int=None, parse_constant=None, infer_missing=False, **kw) -> ~A:
50    @classmethod
51    def from_json(cls: Type[A],
52                  s: JsonData,
53                  *,
54                  parse_float=None,
55                  parse_int=None,
56                  parse_constant=None,
57                  infer_missing=False,
58                  **kw) -> A:
59        kvs = json.loads(s,
60                         parse_float=parse_float,
61                         parse_int=parse_int,
62                         parse_constant=parse_constant,
63                         **kw)
64        return cls.from_dict(kvs, infer_missing=infer_missing)
def to_dict( self, encode_json=False) -> Dict[str, Union[dict, list, str, int, float, bool, NoneType]]:
73    def to_dict(self, encode_json=False) -> Dict[str, Json]:
74        return _asdict(self, encode_json=encode_json)
@classmethod
def from_dict( cls: Type[~A], kvs: Union[dict, list, str, int, float, bool, NoneType], *, infer_missing=False) -> ~A:
66    @classmethod
67    def from_dict(cls: Type[A],
68                  kvs: Json,
69                  *,
70                  infer_missing=False) -> A:
71        return _decode_dataclass(cls, kvs, infer_missing)
@classmethod
def schema( cls: Type[~A], *, infer_missing: bool = False, only=None, exclude=(), many: bool = False, context=None, load_only=(), dump_only=(), partial: bool = False, unknown=None) -> dataclasses_json.mm.SchemaF[~A]:
 76    @classmethod
 77    def schema(cls: Type[A],
 78               *,
 79               infer_missing: bool = False,
 80               only=None,
 81               exclude=(),
 82               many: bool = False,
 83               context=None,
 84               load_only=(),
 85               dump_only=(),
 86               partial: bool = False,
 87               unknown=None) -> "SchemaType[A]":
 88        Schema = build_schema(cls, DataClassJsonMixin, infer_missing, partial)
 89
 90        if unknown is None:
 91            undefined_parameter_action = _undefined_parameter_action_safe(cls)
 92            if undefined_parameter_action is not None:
 93                # We can just make use of the same-named mm keywords
 94                unknown = undefined_parameter_action.name.lower()
 95
 96        return Schema(only=only,
 97                      exclude=exclude,
 98                      many=many,
 99                      context=context,
100                      load_only=load_only,
101                      dump_only=dump_only,
102                      partial=partial,
103                      unknown=unknown)
@dataclass_json
@dataclass
class CaptionsFile:
371@dataclass_json
372@dataclass
373class CaptionsFile:
374    """Subtitles file"""
375
376    path: str
377    """Path to .srt file"""
378
379    language: Optional[LanguageEnum] = None
380    """Language of captions. If None, language will default to audio language"""

Subtitles file

CaptionsFile( path: str, language: Optional[LanguageEnum] = None)
path: str

Path to .srt file

language: Optional[LanguageEnum] = None

Language of captions. If None, language will default to audio language

def to_json( self, *, skipkeys: bool = False, ensure_ascii: bool = True, check_circular: bool = True, allow_nan: bool = True, indent: Union[str, int, NoneType] = None, separators: Optional[Tuple[str, str]] = None, default: Optional[Callable] = None, sort_keys: bool = False, **kw) -> str:
27    def to_json(self,
28                *,
29                skipkeys: bool = False,
30                ensure_ascii: bool = True,
31                check_circular: bool = True,
32                allow_nan: bool = True,
33                indent: Optional[Union[int, str]] = None,
34                separators: Optional[Tuple[str, str]] = None,
35                default: Optional[Callable] = None,
36                sort_keys: bool = False,
37                **kw) -> str:
38        return json.dumps(self.to_dict(encode_json=False),
39                          cls=_ExtendedEncoder,
40                          skipkeys=skipkeys,
41                          ensure_ascii=ensure_ascii,
42                          check_circular=check_circular,
43                          allow_nan=allow_nan,
44                          indent=indent,
45                          separators=separators,
46                          default=default,
47                          sort_keys=sort_keys,
48                          **kw)
@classmethod
def from_json( cls: Type[~A], s: Union[str, bytes, bytearray], *, parse_float=None, parse_int=None, parse_constant=None, infer_missing=False, **kw) -> ~A:
50    @classmethod
51    def from_json(cls: Type[A],
52                  s: JsonData,
53                  *,
54                  parse_float=None,
55                  parse_int=None,
56                  parse_constant=None,
57                  infer_missing=False,
58                  **kw) -> A:
59        kvs = json.loads(s,
60                         parse_float=parse_float,
61                         parse_int=parse_int,
62                         parse_constant=parse_constant,
63                         **kw)
64        return cls.from_dict(kvs, infer_missing=infer_missing)
def to_dict( self, encode_json=False) -> Dict[str, Union[dict, list, str, int, float, bool, NoneType]]:
73    def to_dict(self, encode_json=False) -> Dict[str, Json]:
74        return _asdict(self, encode_json=encode_json)
@classmethod
def from_dict( cls: Type[~A], kvs: Union[dict, list, str, int, float, bool, NoneType], *, infer_missing=False) -> ~A:
66    @classmethod
67    def from_dict(cls: Type[A],
68                  kvs: Json,
69                  *,
70                  infer_missing=False) -> A:
71        return _decode_dataclass(cls, kvs, infer_missing)
@classmethod
def schema( cls: Type[~A], *, infer_missing: bool = False, only=None, exclude=(), many: bool = False, context=None, load_only=(), dump_only=(), partial: bool = False, unknown=None) -> dataclasses_json.mm.SchemaF[~A]:
 76    @classmethod
 77    def schema(cls: Type[A],
 78               *,
 79               infer_missing: bool = False,
 80               only=None,
 81               exclude=(),
 82               many: bool = False,
 83               context=None,
 84               load_only=(),
 85               dump_only=(),
 86               partial: bool = False,
 87               unknown=None) -> "SchemaType[A]":
 88        Schema = build_schema(cls, DataClassJsonMixin, infer_missing, partial)
 89
 90        if unknown is None:
 91            undefined_parameter_action = _undefined_parameter_action_safe(cls)
 92            if undefined_parameter_action is not None:
 93                # We can just make use of the same-named mm keywords
 94                unknown = undefined_parameter_action.name.lower()
 95
 96        return Schema(only=only,
 97                      exclude=exclude,
 98                      many=many,
 99                      context=context,
100                      load_only=load_only,
101                      dump_only=dump_only,
102                      partial=partial,
103                      unknown=unknown)
class PremiereThemeEnum(builtins.str, enum.Enum):
302class PremiereThemeEnum(str, Enum):
303    CLASSIC = "VIDEO_PREMIERE_INTRO_THEME_DEFAULT"
304    ALTERNATIVE = "VIDEO_PREMIERE_INTRO_THEME_ALTERNATIVE"
305    AMBIENT = "VIDEO_PREMIERE_INTRO_THEME_AMBIENT"
306    BRIGHT = "VIDEO_PREMIERE_INTRO_THEME_BRIGHT"
307    CALM = "VIDEO_PREMIERE_INTRO_THEME_CALM"
308    CINEMATIC = "VIDEO_PREMIERE_INTRO_THEME_CINEMATIC"
309    CONTEMPORARY = "VIDEO_PREMIERE_INTRO_THEME_CONTEMPORARY"
310    DRAMATIC = "VIDEO_PREMIERE_INTRO_THEME_DRAMATIC"
311    FUNKY = "VIDEO_PREMIERE_INTRO_THEME_FUNKY"
312    GENTLE = "VIDEO_PREMIERE_INTRO_THEME_GENTLE"
313    HAPPY = "VIDEO_PREMIERE_INTRO_THEME_HAPPY"
314    INSPIRATIONAL = "VIDEO_PREMIERE_INTRO_THEME_INSPIRATIONAL"
315    KIDS = "VIDEO_PREMIERE_INTRO_THEME_KIDS"
316    SCI_FI = "VIDEO_PREMIERE_INTRO_THEME_SCI_FI"
317    SPORTS = "VIDEO_PREMIERE_INTRO_THEME_SPORTS"

An enumeration.

CLASSIC = <PremiereThemeEnum.CLASSIC: 'VIDEO_PREMIERE_INTRO_THEME_DEFAULT'>
ALTERNATIVE = <PremiereThemeEnum.ALTERNATIVE: 'VIDEO_PREMIERE_INTRO_THEME_ALTERNATIVE'>
AMBIENT = <PremiereThemeEnum.AMBIENT: 'VIDEO_PREMIERE_INTRO_THEME_AMBIENT'>
BRIGHT = <PremiereThemeEnum.BRIGHT: 'VIDEO_PREMIERE_INTRO_THEME_BRIGHT'>
CALM = <PremiereThemeEnum.CALM: 'VIDEO_PREMIERE_INTRO_THEME_CALM'>
CINEMATIC = <PremiereThemeEnum.CINEMATIC: 'VIDEO_PREMIERE_INTRO_THEME_CINEMATIC'>
CONTEMPORARY = <PremiereThemeEnum.CONTEMPORARY: 'VIDEO_PREMIERE_INTRO_THEME_CONTEMPORARY'>
DRAMATIC = <PremiereThemeEnum.DRAMATIC: 'VIDEO_PREMIERE_INTRO_THEME_DRAMATIC'>
FUNKY = <PremiereThemeEnum.FUNKY: 'VIDEO_PREMIERE_INTRO_THEME_FUNKY'>
GENTLE = <PremiereThemeEnum.GENTLE: 'VIDEO_PREMIERE_INTRO_THEME_GENTLE'>
HAPPY = <PremiereThemeEnum.HAPPY: 'VIDEO_PREMIERE_INTRO_THEME_HAPPY'>
INSPIRATIONAL = <PremiereThemeEnum.INSPIRATIONAL: 'VIDEO_PREMIERE_INTRO_THEME_INSPIRATIONAL'>
KIDS = <PremiereThemeEnum.KIDS: 'VIDEO_PREMIERE_INTRO_THEME_KIDS'>
SCI_FI = <PremiereThemeEnum.SCI_FI: 'VIDEO_PREMIERE_INTRO_THEME_SCI_FI'>
SPORTS = <PremiereThemeEnum.SPORTS: 'VIDEO_PREMIERE_INTRO_THEME_SPORTS'>
Inherited Members
enum.Enum
name
value
builtins.str
encode
replace
split
rsplit
join
capitalize
casefold
title
center
count
expandtabs
find
partition
index
ljust
lower
lstrip
rfind
rindex
rjust
rstrip
rpartition
splitlines
strip
swapcase
translate
upper
startswith
endswith
removeprefix
removesuffix
isascii
islower
isupper
istitle
isspace
isdecimal
isdigit
isnumeric
isalpha
isalnum
isidentifier
isprintable
zfill
format
format_map
maketrans
class PremiereDurationEnum(builtins.str, enum.Enum):
294class PremiereDurationEnum(str, Enum):
295    ONE_MIN = "60"
296    TWO_MIN = "120"
297    THREE_MIN = "180"
298    FOUR_MIN = "240"
299    FIVE_MIN = "300"

An enumeration.

ONE_MIN = <PremiereDurationEnum.ONE_MIN: '60'>
TWO_MIN = <PremiereDurationEnum.TWO_MIN: '120'>
THREE_MIN = <PremiereDurationEnum.THREE_MIN: '180'>
FOUR_MIN = <PremiereDurationEnum.FOUR_MIN: '240'>
FIVE_MIN = <PremiereDurationEnum.FIVE_MIN: '300'>
Inherited Members
enum.Enum
name
value
builtins.str
encode
replace
split
rsplit
join
capitalize
casefold
title
center
count
expandtabs
find
partition
index
ljust
lower
lstrip
rfind
rindex
rjust
rstrip
rpartition
splitlines
strip
swapcase
translate
upper
startswith
endswith
removeprefix
removesuffix
isascii
islower
isupper
istitle
isspace
isdecimal
isdigit
isnumeric
isalpha
isalnum
isidentifier
isprintable
zfill
format
format_map
maketrans
class ThumbnailFormatEnum(builtins.str, enum.Enum):
289class ThumbnailFormatEnum(str, Enum):
290    PNG = "CUSTOM_THUMBNAIL_IMAGE_FORMAT_PNG"
291    JPG = "CUSTOM_THUMBNAIL_IMAGE_FORMAT_JPEG"

An enumeration.

PNG = <ThumbnailFormatEnum.PNG: 'CUSTOM_THUMBNAIL_IMAGE_FORMAT_PNG'>
JPG = <ThumbnailFormatEnum.JPG: 'CUSTOM_THUMBNAIL_IMAGE_FORMAT_JPEG'>
Inherited Members
enum.Enum
name
value
builtins.str
encode
replace
split
rsplit
join
capitalize
casefold
title
center
count
expandtabs
find
partition
index
ljust
lower
lstrip
rfind
rindex
rjust
rstrip
rpartition
splitlines
strip
swapcase
translate
upper
startswith
endswith
removeprefix
removesuffix
isascii
islower
isupper
istitle
isspace
isdecimal
isdigit
isnumeric
isalpha
isalnum
isidentifier
isprintable
zfill
format
format_map
maketrans
class CommentsSortOrderEnum(builtins.str, enum.Enum):
284class CommentsSortOrderEnum(str, Enum):
285    LATEST = "MDE_COMMENT_SORT_ORDER_LATEST"
286    TOP = "MDE_COMMENT_SORT_ORDER_TOP"

An enumeration.

LATEST = <CommentsSortOrderEnum.LATEST: 'MDE_COMMENT_SORT_ORDER_LATEST'>
TOP = <CommentsSortOrderEnum.TOP: 'MDE_COMMENT_SORT_ORDER_TOP'>
Inherited Members
enum.Enum
name
value
builtins.str
encode
replace
split
rsplit
join
capitalize
casefold
title
center
count
expandtabs
find
partition
index
ljust
lower
lstrip
rfind
rindex
rjust
rstrip
rpartition
splitlines
strip
swapcase
translate
upper
startswith
endswith
removeprefix
removesuffix
isascii
islower
isupper
istitle
isspace
isdecimal
isdigit
isnumeric
isalpha
isalnum
isidentifier
isprintable
zfill
format
format_map
maketrans
class AllowCommentsEnum(builtins.str, enum.Enum):
277class AllowCommentsEnum(str, Enum):
278    ALL_COMMENTS = "ALL_COMMENTS"
279    HOLD_INAPPROPRIATE = "AUTOMATED_COMMENTS"
280    HOLD_INAPPROPRIATE_STRICT = "AUTO_MODERATED_COMMENTS_HOLD_MORE"
281    HOLD_ALL = "APPROVED_COMMENTS"

An enumeration.

ALL_COMMENTS = <AllowCommentsEnum.ALL_COMMENTS: 'ALL_COMMENTS'>
HOLD_INAPPROPRIATE = <AllowCommentsEnum.HOLD_INAPPROPRIATE: 'AUTOMATED_COMMENTS'>
HOLD_INAPPROPRIATE_STRICT = <AllowCommentsEnum.HOLD_INAPPROPRIATE_STRICT: 'AUTO_MODERATED_COMMENTS_HOLD_MORE'>
HOLD_ALL = <AllowCommentsEnum.HOLD_ALL: 'APPROVED_COMMENTS'>
Inherited Members
enum.Enum
name
value
builtins.str
encode
replace
split
rsplit
join
capitalize
casefold
title
center
count
expandtabs
find
partition
index
ljust
lower
lstrip
rfind
rindex
rjust
rstrip
rpartition
splitlines
strip
swapcase
translate
upper
startswith
endswith
removeprefix
removesuffix
isascii
islower
isupper
istitle
isspace
isdecimal
isdigit
isnumeric
isalpha
isalnum
isidentifier
isprintable
zfill
format
format_map
maketrans
class LicenseEnum(builtins.str, enum.Enum):
272class LicenseEnum(str, Enum):
273    STANDARD = "standard"
274    CREATIVE_COMMONS = "creative_commons"

An enumeration.

STANDARD = <LicenseEnum.STANDARD: 'standard'>
CREATIVE_COMMONS = <LicenseEnum.CREATIVE_COMMONS: 'creative_commons'>
Inherited Members
enum.Enum
name
value
builtins.str
encode
replace
split
rsplit
join
capitalize
casefold
title
center
count
expandtabs
find
partition
index
ljust
lower
lstrip
rfind
rindex
rjust
rstrip
rpartition
splitlines
strip
swapcase
translate
upper
startswith
endswith
removeprefix
removesuffix
isascii
islower
isupper
istitle
isspace
isdecimal
isdigit
isnumeric
isalpha
isalnum
isidentifier
isprintable
zfill
format
format_map
maketrans
class LanguageEnum(builtins.str, enum.Enum):
 35class LanguageEnum(str, Enum):
 36    NOT_APPLICABLE = "zxx"
 37    ABKHAZIAN = "ab"
 38    AFAR = "aa"
 39    AFRIKAANS = "af"
 40    AKAN = "ak"
 41    AKKADIAN = "akk"
 42    ALBANIAN = "sq"
 43    AMERICAN_SIGN_LANGUAGE = "ase"
 44    AMHARIC = "am"
 45    ARABIC = "ar"
 46    ARAMAIC = "arc"
 47    ARMENIAN = "hy"
 48    ASSAMESE = "as"
 49    AYMARA = "ay"
 50    AZERBAIJANI = "az"
 51    BAMBARA = "bm"
 52    BANGLA = "bn"
 53    BANGLA_INDIA = "bn-IN"
 54    BASHKIR = "ba"
 55    BASQUE = "eu"
 56    BELARUSIAN = "be"
 57    BHOJPURI = "bho"
 58    BISLAMA = "bi"
 59    BODO = "brx"
 60    BOSNIAN = "bs"
 61    BRETON = "br"
 62    BULGARIAN = "bg"
 63    BURMESE = "my"
 64    CANTONESE = "yue"
 65    CANTONESE_HONG_KONG = "yue-HK"
 66    CATALAN = "ca"
 67    CHEROKEE = "chr"
 68    CHINESE = "zh"
 69    CHINESE_CHINA = "zh-CN"
 70    CHINESE_HONG_KONG = "zh-HK"
 71    CHINESE_SIMPLIFIED = "zh-Hans"
 72    CHINESE_SINGAPORE = "zh-SG"
 73    CHINESE_TAIWAN = "zh-TW"
 74    CHINESE_TRADITIONAL = "zh-Hant"
 75    CHOCTAW = "cho"
 76    COPTIC = "cop"
 77    CORSICAN = "co"
 78    CREE = "cr"
 79    CROATIAN = "hr"
 80    CZECH = "cs"
 81    DANISH = "da"
 82    DOGRI = "doi"
 83    DUTCH = "nl"
 84    DUTCH_BELGIUM = "nl-BE"
 85    DUTCH_NETHERLANDS = "nl-NL"
 86    DZONGKHA = "dz"
 87    ENGLISH = "en"
 88    ENGLISH_AUSTRALIA = "en-AU"
 89    ENGLISH_CANADA = "en-CA"
 90    ENGLISH_INDIA = "en-IN"
 91    ENGLISH_IRELAND = "en-IE"
 92    ENGLISH_UNITED_KINGDOM = "en-GB"
 93    ENGLISH_UNITED_STATES = "en-US"
 94    ESPERANTO = "eo"
 95    ESTONIAN = "et"
 96    EWE = "ee"
 97    FAROESE = "fo"
 98    FIJIAN = "fj"
 99    FILIPINO = "fil"
100    FINNISH = "fi"
101    FRENCH = "fr"
102    FRENCH_BELGIUM = "fr-BE"
103    FRENCH_CANADA = "fr-CA"
104    FRENCH_FRANCE = "fr-FR"
105    FRENCH_SWITZERLAND = "fr-CH"
106    FULA = "ff"
107    GALICIAN = "gl"
108    GANDA = "lg"
109    GEORGIAN = "ka"
110    GERMAN = "de"
111    GERMAN_AUSTRIA = "de-AT"
112    GERMAN_GERMANY = "de-DE"
113    GERMAN_SWITZERLAND = "de-CH"
114    GREEK = "el"
115    GUARANI = "gn"
116    GUJARATI = "gu"
117    GUSII = "guz"
118    HAITIAN_CREOLE = "ht"
119    HAKKA_CHINESE = "hak"
120    HAKKA_CHINESE_TAIWAN = "hak-TW"
121    HARYANVI = "bgc"
122    HAUSA = "ha"
123    HAWAIIAN = "haw"
124    HEBREW = "he"
125    HINDI = "hi"
126    HINDI_LATIN = "hi-Latn"
127    HIRI_MOTU = "ho"
128    HUNGARIAN = "hu"
129    ICELANDIC = "is"
130    IGBO = "ig"
131    INDONESIAN = "id"
132    INTERLINGUA = "ia"
133    INTERLINGUE = "ie"
134    INUKTITUT = "iu"
135    INUPIAQ = "ik"
136    IRISH = "ga"
137    ITALIAN = "it"
138    JAPANESE = "ja"
139    JAVANESE = "jv"
140    KALAALLISUT = "kl"
141    KALENJIN = "kln"
142    KAMBA = "kam"
143    KANNADA = "kn"
144    KASHMIRI = "ks"
145    KAZAKH = "kk"
146    KHMER = "km"
147    KIKUYU = "ki"
148    KINYARWANDA = "rw"
149    KLINGON = "tlh"
150    KONKANI = "kok"
151    KOREAN = "ko"
152    KURDISH = "ku"
153    KYRGYZ = "ky"
154    LADINO = "lad"
155    LAO = "lo"
156    LATIN = "la"
157    LATVIAN = "lv"
158    LINGALA = "ln"
159    LITHUANIAN = "lt"
160    LUBA_KATANGA = "lu"
161    LUO = "luo"
162    LUXEMBOURGISH = "lb"
163    LUYIA = "luy"
164    MACEDONIAN = "mk"
165    MAITHILI = "mai"
166    MALAGASY = "mg"
167    MALAY = "ms"
168    MALAY_SINGAPORE = "ms-SG"
169    MALAYALAM = "ml"
170    MALTESE = "mt"
171    MANIPURI = "mni"
172    MAORI = "mi"
173    MARATHI = "mr"
174    MASAI = "mas"
175    MERU = "mer"
176    MIN_NAN_CHINESE = "nan"
177    MIN_NAN_CHINESE_TAIWAN = "nan-TW"
178    MIXE = "mco"
179    MIZO = "lus"
180    MONGOLIAN = "mn"
181    MONGOLIAN_MONGOLIAN = "mn-M"
182    NAURU = "na"
183    NAVAJO = "nv"
184    NEPALI = "ne"
185    NIGERIAN_PIDGIN = "pcm"
186    NORTH_NDEBELE = "nd"
187    NORTHERN_SOTHO = "nso"
188    NORWEGIAN = "no"
189    OCCITAN = "oc"
190    ODIA = "or"
191    OROMO = "om"
192    PAPIAMENTO = "pap"
193    PASHTO = "ps"
194    PERSIAN = "fa"
195    PERSIAN_AFGHANISTAN = "fa-AF"
196    PERSIAN_IRAN = "fa-IR"
197    POLISH = "pl"
198    PORTUGUESE = "pt"
199    PORTUGUESE_BRAZIL = "pt-BR"
200    PORTUGUESE_PORTUGAL = "pt-PT"
201    PUNJABI = "pa"
202    QUECHUA = "qu"
203    ROMANIAN = "ro"
204    ROMANIAN_MOLDOVA = "ro-MD"
205    ROMANSH = "rm"
206    RUNDI = "rn"
207    RUSSIAN = "ru"
208    RUSSIAN_LATIN = "ru-Latn"
209    SAMOAN = "sm"
210    SANGO = "sg"
211    SANSKRIT = "sa"
212    SANTALI = "sat"
213    SARDINIAN = "sc"
214    SCOTTISH_GAELIC = "gd"
215    SERBIAN = "sr"
216    SERBIAN_CYRILLIC = "hr-Cyrl"
217    SERBIAN_LATIN = "sr-Latn"
218    SERBO_CROATIAN = "sh"
219    SHERDUKPEN = "sdp"
220    SHONA = "sn"
221    SICILIAN = "scn"
222    SINDHI = "sd"
223    SINHALA = "si"
224    SLOVAK = "sk"
225    SLOVENIAN = "sl"
226    SOMALI = "so"
227    SOUTH_NDEBELE = "nr"
228    SOUTHERN_SOTHO = "st"
229    SPANISH = "es"
230    SPANISH_LATIN_AMERICA = "es-419"
231    SPANISH_MEXICO = "es-MX"
232    SPANISH_SPAIN = "es-ES"
233    SPANISH_UNITED_STATES = "es-US"
234    SUNDANESE = "su"
235    SWAHILI = "sw"
236    SWATI = "ss"
237    SWEDISH = "sv"
238    TAGALOG = "tl"
239    TAJIK = "tg"
240    TAMIL = "ta"
241    TATAR = "tt"
242    TELUGU = "te"
243    THAI = "th"
244    TIBETAN = "bo"
245    TIGRINYA = "ti"
246    TOK_PISIN = "tpi"
247    TOKI_PONA = "tok"
248    TONGAN = "to"
249    TSONGA = "ts"
250    TSWANA = "tn"
251    TURKISH = "tr"
252    TURKMEN = "tk"
253    TWI = "tw"
254    UKRAINIAN = "uk"
255    URDU = "ur"
256    UYGHUR = "ug"
257    UZBEK = "uz"
258    VENDA = "ve"
259    VIETNAMESE = "vi"
260    VOLAPÜK = "vo"
261    VÕRO = "vro"
262    WELSH = "cy"
263    WESTERN_FRISIAN = "fy"
264    WOLAYTTA = "wal"
265    WOLOF = "wo"
266    XHOSA = "xh"
267    YIDDISH = "yi"
268    YORUBA = "yo"
269    ZULU = "zu"

An enumeration.

NOT_APPLICABLE = <LanguageEnum.NOT_APPLICABLE: 'zxx'>
ABKHAZIAN = <LanguageEnum.ABKHAZIAN: 'ab'>
AFAR = <LanguageEnum.AFAR: 'aa'>
AFRIKAANS = <LanguageEnum.AFRIKAANS: 'af'>
AKAN = <LanguageEnum.AKAN: 'ak'>
AKKADIAN = <LanguageEnum.AKKADIAN: 'akk'>
ALBANIAN = <LanguageEnum.ALBANIAN: 'sq'>
AMERICAN_SIGN_LANGUAGE = <LanguageEnum.AMERICAN_SIGN_LANGUAGE: 'ase'>
AMHARIC = <LanguageEnum.AMHARIC: 'am'>
ARABIC = <LanguageEnum.ARABIC: 'ar'>
ARAMAIC = <LanguageEnum.ARAMAIC: 'arc'>
ARMENIAN = <LanguageEnum.ARMENIAN: 'hy'>
ASSAMESE = <LanguageEnum.ASSAMESE: 'as'>
AYMARA = <LanguageEnum.AYMARA: 'ay'>
AZERBAIJANI = <LanguageEnum.AZERBAIJANI: 'az'>
BAMBARA = <LanguageEnum.BAMBARA: 'bm'>
BANGLA = <LanguageEnum.BANGLA: 'bn'>
BANGLA_INDIA = <LanguageEnum.BANGLA_INDIA: 'bn-IN'>
BASHKIR = <LanguageEnum.BASHKIR: 'ba'>
BASQUE = <LanguageEnum.BASQUE: 'eu'>
BELARUSIAN = <LanguageEnum.BELARUSIAN: 'be'>
BHOJPURI = <LanguageEnum.BHOJPURI: 'bho'>
BISLAMA = <LanguageEnum.BISLAMA: 'bi'>
BODO = <LanguageEnum.BODO: 'brx'>
BOSNIAN = <LanguageEnum.BOSNIAN: 'bs'>
BRETON = <LanguageEnum.BRETON: 'br'>
BULGARIAN = <LanguageEnum.BULGARIAN: 'bg'>
BURMESE = <LanguageEnum.BURMESE: 'my'>
CANTONESE = <LanguageEnum.CANTONESE: 'yue'>
CANTONESE_HONG_KONG = <LanguageEnum.CANTONESE_HONG_KONG: 'yue-HK'>
CATALAN = <LanguageEnum.CATALAN: 'ca'>
CHEROKEE = <LanguageEnum.CHEROKEE: 'chr'>
CHINESE = <LanguageEnum.CHINESE: 'zh'>
CHINESE_CHINA = <LanguageEnum.CHINESE_CHINA: 'zh-CN'>
CHINESE_HONG_KONG = <LanguageEnum.CHINESE_HONG_KONG: 'zh-HK'>
CHINESE_SIMPLIFIED = <LanguageEnum.CHINESE_SIMPLIFIED: 'zh-Hans'>
CHINESE_SINGAPORE = <LanguageEnum.CHINESE_SINGAPORE: 'zh-SG'>
CHINESE_TAIWAN = <LanguageEnum.CHINESE_TAIWAN: 'zh-TW'>
CHINESE_TRADITIONAL = <LanguageEnum.CHINESE_TRADITIONAL: 'zh-Hant'>
CHOCTAW = <LanguageEnum.CHOCTAW: 'cho'>
COPTIC = <LanguageEnum.COPTIC: 'cop'>
CORSICAN = <LanguageEnum.CORSICAN: 'co'>
CREE = <LanguageEnum.CREE: 'cr'>
CROATIAN = <LanguageEnum.CROATIAN: 'hr'>
CZECH = <LanguageEnum.CZECH: 'cs'>
DANISH = <LanguageEnum.DANISH: 'da'>
DOGRI = <LanguageEnum.DOGRI: 'doi'>
DUTCH = <LanguageEnum.DUTCH: 'nl'>
DUTCH_BELGIUM = <LanguageEnum.DUTCH_BELGIUM: 'nl-BE'>
DUTCH_NETHERLANDS = <LanguageEnum.DUTCH_NETHERLANDS: 'nl-NL'>
DZONGKHA = <LanguageEnum.DZONGKHA: 'dz'>
ENGLISH = <LanguageEnum.ENGLISH: 'en'>
ENGLISH_AUSTRALIA = <LanguageEnum.ENGLISH_AUSTRALIA: 'en-AU'>
ENGLISH_CANADA = <LanguageEnum.ENGLISH_CANADA: 'en-CA'>
ENGLISH_INDIA = <LanguageEnum.ENGLISH_INDIA: 'en-IN'>
ENGLISH_IRELAND = <LanguageEnum.ENGLISH_IRELAND: 'en-IE'>
ENGLISH_UNITED_KINGDOM = <LanguageEnum.ENGLISH_UNITED_KINGDOM: 'en-GB'>
ENGLISH_UNITED_STATES = <LanguageEnum.ENGLISH_UNITED_STATES: 'en-US'>
ESPERANTO = <LanguageEnum.ESPERANTO: 'eo'>
ESTONIAN = <LanguageEnum.ESTONIAN: 'et'>
EWE = <LanguageEnum.EWE: 'ee'>
FAROESE = <LanguageEnum.FAROESE: 'fo'>
FIJIAN = <LanguageEnum.FIJIAN: 'fj'>
FILIPINO = <LanguageEnum.FILIPINO: 'fil'>
FINNISH = <LanguageEnum.FINNISH: 'fi'>
FRENCH = <LanguageEnum.FRENCH: 'fr'>
FRENCH_BELGIUM = <LanguageEnum.FRENCH_BELGIUM: 'fr-BE'>
FRENCH_CANADA = <LanguageEnum.FRENCH_CANADA: 'fr-CA'>
FRENCH_FRANCE = <LanguageEnum.FRENCH_FRANCE: 'fr-FR'>
FRENCH_SWITZERLAND = <LanguageEnum.FRENCH_SWITZERLAND: 'fr-CH'>
FULA = <LanguageEnum.FULA: 'ff'>
GALICIAN = <LanguageEnum.GALICIAN: 'gl'>
GANDA = <LanguageEnum.GANDA: 'lg'>
GEORGIAN = <LanguageEnum.GEORGIAN: 'ka'>
GERMAN = <LanguageEnum.GERMAN: 'de'>
GERMAN_AUSTRIA = <LanguageEnum.GERMAN_AUSTRIA: 'de-AT'>
GERMAN_GERMANY = <LanguageEnum.GERMAN_GERMANY: 'de-DE'>
GERMAN_SWITZERLAND = <LanguageEnum.GERMAN_SWITZERLAND: 'de-CH'>
GREEK = <LanguageEnum.GREEK: 'el'>
GUARANI = <LanguageEnum.GUARANI: 'gn'>
GUJARATI = <LanguageEnum.GUJARATI: 'gu'>
GUSII = <LanguageEnum.GUSII: 'guz'>
HAITIAN_CREOLE = <LanguageEnum.HAITIAN_CREOLE: 'ht'>
HAKKA_CHINESE = <LanguageEnum.HAKKA_CHINESE: 'hak'>
HAKKA_CHINESE_TAIWAN = <LanguageEnum.HAKKA_CHINESE_TAIWAN: 'hak-TW'>
HARYANVI = <LanguageEnum.HARYANVI: 'bgc'>
HAUSA = <LanguageEnum.HAUSA: 'ha'>
HAWAIIAN = <LanguageEnum.HAWAIIAN: 'haw'>
HEBREW = <LanguageEnum.HEBREW: 'he'>
HINDI = <LanguageEnum.HINDI: 'hi'>
HINDI_LATIN = <LanguageEnum.HINDI_LATIN: 'hi-Latn'>
HIRI_MOTU = <LanguageEnum.HIRI_MOTU: 'ho'>
HUNGARIAN = <LanguageEnum.HUNGARIAN: 'hu'>
ICELANDIC = <LanguageEnum.ICELANDIC: 'is'>
IGBO = <LanguageEnum.IGBO: 'ig'>
INDONESIAN = <LanguageEnum.INDONESIAN: 'id'>
INTERLINGUA = <LanguageEnum.INTERLINGUA: 'ia'>
INTERLINGUE = <LanguageEnum.INTERLINGUE: 'ie'>
INUKTITUT = <LanguageEnum.INUKTITUT: 'iu'>
INUPIAQ = <LanguageEnum.INUPIAQ: 'ik'>
IRISH = <LanguageEnum.IRISH: 'ga'>
ITALIAN = <LanguageEnum.ITALIAN: 'it'>
JAPANESE = <LanguageEnum.JAPANESE: 'ja'>
JAVANESE = <LanguageEnum.JAVANESE: 'jv'>
KALAALLISUT = <LanguageEnum.KALAALLISUT: 'kl'>
KALENJIN = <LanguageEnum.KALENJIN: 'kln'>
KAMBA = <LanguageEnum.KAMBA: 'kam'>
KANNADA = <LanguageEnum.KANNADA: 'kn'>
KASHMIRI = <LanguageEnum.KASHMIRI: 'ks'>
KAZAKH = <LanguageEnum.KAZAKH: 'kk'>
KHMER = <LanguageEnum.KHMER: 'km'>
KIKUYU = <LanguageEnum.KIKUYU: 'ki'>
KINYARWANDA = <LanguageEnum.KINYARWANDA: 'rw'>
KLINGON = <LanguageEnum.KLINGON: 'tlh'>
KONKANI = <LanguageEnum.KONKANI: 'kok'>
KOREAN = <LanguageEnum.KOREAN: 'ko'>
KURDISH = <LanguageEnum.KURDISH: 'ku'>
KYRGYZ = <LanguageEnum.KYRGYZ: 'ky'>
LADINO = <LanguageEnum.LADINO: 'lad'>
LAO = <LanguageEnum.LAO: 'lo'>
LATIN = <LanguageEnum.LATIN: 'la'>
LATVIAN = <LanguageEnum.LATVIAN: 'lv'>
LINGALA = <LanguageEnum.LINGALA: 'ln'>
LITHUANIAN = <LanguageEnum.LITHUANIAN: 'lt'>
LUBA_KATANGA = <LanguageEnum.LUBA_KATANGA: 'lu'>
LUO = <LanguageEnum.LUO: 'luo'>
LUXEMBOURGISH = <LanguageEnum.LUXEMBOURGISH: 'lb'>
LUYIA = <LanguageEnum.LUYIA: 'luy'>
MACEDONIAN = <LanguageEnum.MACEDONIAN: 'mk'>
MAITHILI = <LanguageEnum.MAITHILI: 'mai'>
MALAGASY = <LanguageEnum.MALAGASY: 'mg'>
MALAY = <LanguageEnum.MALAY: 'ms'>
MALAY_SINGAPORE = <LanguageEnum.MALAY_SINGAPORE: 'ms-SG'>
MALAYALAM = <LanguageEnum.MALAYALAM: 'ml'>
MALTESE = <LanguageEnum.MALTESE: 'mt'>
MANIPURI = <LanguageEnum.MANIPURI: 'mni'>
MAORI = <LanguageEnum.MAORI: 'mi'>
MARATHI = <LanguageEnum.MARATHI: 'mr'>
MASAI = <LanguageEnum.MASAI: 'mas'>
MERU = <LanguageEnum.MERU: 'mer'>
MIN_NAN_CHINESE = <LanguageEnum.MIN_NAN_CHINESE: 'nan'>
MIN_NAN_CHINESE_TAIWAN = <LanguageEnum.MIN_NAN_CHINESE_TAIWAN: 'nan-TW'>
MIXE = <LanguageEnum.MIXE: 'mco'>
MIZO = <LanguageEnum.MIZO: 'lus'>
MONGOLIAN = <LanguageEnum.MONGOLIAN: 'mn'>
MONGOLIAN_MONGOLIAN = <LanguageEnum.MONGOLIAN_MONGOLIAN: 'mn-M'>
NAURU = <LanguageEnum.NAURU: 'na'>
NAVAJO = <LanguageEnum.NAVAJO: 'nv'>
NEPALI = <LanguageEnum.NEPALI: 'ne'>
NIGERIAN_PIDGIN = <LanguageEnum.NIGERIAN_PIDGIN: 'pcm'>
NORTH_NDEBELE = <LanguageEnum.NORTH_NDEBELE: 'nd'>
NORTHERN_SOTHO = <LanguageEnum.NORTHERN_SOTHO: 'nso'>
NORWEGIAN = <LanguageEnum.NORWEGIAN: 'no'>
OCCITAN = <LanguageEnum.OCCITAN: 'oc'>
ODIA = <LanguageEnum.ODIA: 'or'>
OROMO = <LanguageEnum.OROMO: 'om'>
PAPIAMENTO = <LanguageEnum.PAPIAMENTO: 'pap'>
PASHTO = <LanguageEnum.PASHTO: 'ps'>
PERSIAN = <LanguageEnum.PERSIAN: 'fa'>
PERSIAN_AFGHANISTAN = <LanguageEnum.PERSIAN_AFGHANISTAN: 'fa-AF'>
PERSIAN_IRAN = <LanguageEnum.PERSIAN_IRAN: 'fa-IR'>
POLISH = <LanguageEnum.POLISH: 'pl'>
PORTUGUESE = <LanguageEnum.PORTUGUESE: 'pt'>
PORTUGUESE_BRAZIL = <LanguageEnum.PORTUGUESE_BRAZIL: 'pt-BR'>
PORTUGUESE_PORTUGAL = <LanguageEnum.PORTUGUESE_PORTUGAL: 'pt-PT'>
PUNJABI = <LanguageEnum.PUNJABI: 'pa'>
QUECHUA = <LanguageEnum.QUECHUA: 'qu'>
ROMANIAN = <LanguageEnum.ROMANIAN: 'ro'>
ROMANIAN_MOLDOVA = <LanguageEnum.ROMANIAN_MOLDOVA: 'ro-MD'>
ROMANSH = <LanguageEnum.ROMANSH: 'rm'>
RUNDI = <LanguageEnum.RUNDI: 'rn'>
RUSSIAN = <LanguageEnum.RUSSIAN: 'ru'>
RUSSIAN_LATIN = <LanguageEnum.RUSSIAN_LATIN: 'ru-Latn'>
SAMOAN = <LanguageEnum.SAMOAN: 'sm'>
SANGO = <LanguageEnum.SANGO: 'sg'>
SANSKRIT = <LanguageEnum.SANSKRIT: 'sa'>
SANTALI = <LanguageEnum.SANTALI: 'sat'>
SARDINIAN = <LanguageEnum.SARDINIAN: 'sc'>
SCOTTISH_GAELIC = <LanguageEnum.SCOTTISH_GAELIC: 'gd'>
SERBIAN = <LanguageEnum.SERBIAN: 'sr'>
SERBIAN_CYRILLIC = <LanguageEnum.SERBIAN_CYRILLIC: 'hr-Cyrl'>
SERBIAN_LATIN = <LanguageEnum.SERBIAN_LATIN: 'sr-Latn'>
SERBO_CROATIAN = <LanguageEnum.SERBO_CROATIAN: 'sh'>
SHERDUKPEN = <LanguageEnum.SHERDUKPEN: 'sdp'>
SHONA = <LanguageEnum.SHONA: 'sn'>
SICILIAN = <LanguageEnum.SICILIAN: 'scn'>
SINDHI = <LanguageEnum.SINDHI: 'sd'>
SINHALA = <LanguageEnum.SINHALA: 'si'>
SLOVAK = <LanguageEnum.SLOVAK: 'sk'>
SLOVENIAN = <LanguageEnum.SLOVENIAN: 'sl'>
SOMALI = <LanguageEnum.SOMALI: 'so'>
SOUTH_NDEBELE = <LanguageEnum.SOUTH_NDEBELE: 'nr'>
SOUTHERN_SOTHO = <LanguageEnum.SOUTHERN_SOTHO: 'st'>
SPANISH = <LanguageEnum.SPANISH: 'es'>
SPANISH_LATIN_AMERICA = <LanguageEnum.SPANISH_LATIN_AMERICA: 'es-419'>
SPANISH_MEXICO = <LanguageEnum.SPANISH_MEXICO: 'es-MX'>
SPANISH_SPAIN = <LanguageEnum.SPANISH_SPAIN: 'es-ES'>
SPANISH_UNITED_STATES = <LanguageEnum.SPANISH_UNITED_STATES: 'es-US'>
SUNDANESE = <LanguageEnum.SUNDANESE: 'su'>
SWAHILI = <LanguageEnum.SWAHILI: 'sw'>
SWATI = <LanguageEnum.SWATI: 'ss'>
SWEDISH = <LanguageEnum.SWEDISH: 'sv'>
TAGALOG = <LanguageEnum.TAGALOG: 'tl'>
TAJIK = <LanguageEnum.TAJIK: 'tg'>
TAMIL = <LanguageEnum.TAMIL: 'ta'>
TATAR = <LanguageEnum.TATAR: 'tt'>
TELUGU = <LanguageEnum.TELUGU: 'te'>
THAI = <LanguageEnum.THAI: 'th'>
TIBETAN = <LanguageEnum.TIBETAN: 'bo'>
TIGRINYA = <LanguageEnum.TIGRINYA: 'ti'>
TOK_PISIN = <LanguageEnum.TOK_PISIN: 'tpi'>
TOKI_PONA = <LanguageEnum.TOKI_PONA: 'tok'>
TONGAN = <LanguageEnum.TONGAN: 'to'>
TSONGA = <LanguageEnum.TSONGA: 'ts'>
TSWANA = <LanguageEnum.TSWANA: 'tn'>
TURKISH = <LanguageEnum.TURKISH: 'tr'>
TURKMEN = <LanguageEnum.TURKMEN: 'tk'>
TWI = <LanguageEnum.TWI: 'tw'>
UKRAINIAN = <LanguageEnum.UKRAINIAN: 'uk'>
URDU = <LanguageEnum.URDU: 'ur'>
UYGHUR = <LanguageEnum.UYGHUR: 'ug'>
UZBEK = <LanguageEnum.UZBEK: 'uz'>
VENDA = <LanguageEnum.VENDA: 've'>
VIETNAMESE = <LanguageEnum.VIETNAMESE: 'vi'>
VOLAPÜK = <LanguageEnum.VOLAPÜK: 'vo'>
VÕRO = <LanguageEnum.VÕRO: 'vro'>
WELSH = <LanguageEnum.WELSH: 'cy'>
WESTERN_FRISIAN = <LanguageEnum.WESTERN_FRISIAN: 'fy'>
WOLAYTTA = <LanguageEnum.WOLAYTTA: 'wal'>
WOLOF = <LanguageEnum.WOLOF: 'wo'>
XHOSA = <LanguageEnum.XHOSA: 'xh'>
YIDDISH = <LanguageEnum.YIDDISH: 'yi'>
YORUBA = <LanguageEnum.YORUBA: 'yo'>
ZULU = <LanguageEnum.ZULU: 'zu'>
Inherited Members
enum.Enum
name
value
builtins.str
encode
replace
split
rsplit
join
capitalize
casefold
title
center
count
expandtabs
find
partition
index
ljust
lower
lstrip
rfind
rindex
rjust
rstrip
rpartition
splitlines
strip
swapcase
translate
upper
startswith
endswith
removeprefix
removesuffix
isascii
islower
isupper
istitle
isspace
isdecimal
isdigit
isnumeric
isalpha
isalnum
isidentifier
isprintable
zfill
format
format_map
maketrans
class CategoryEnum(builtins.int, enum.Enum):
17class CategoryEnum(int, Enum):
18    FILM_ANIMATION = 1
19    AUTOS_VEHICLES = 2
20    MUSIC = 10
21    PETS_ANIMALS = 15
22    SPORTS = 17
23    TRAVEL_EVENTS = 19
24    GAMING = 20
25    PEOPLE_BLOGS = 22
26    COMEDY = 23
27    ENTERTAINMENT = 24
28    NEWS_POLITICS = 25
29    HOWTO_STYLE = 26
30    EDUCATION = 27
31    SCIENCE_TECH = 28
32    NONPROFITS_ACTIVISM = 29

An enumeration.

FILM_ANIMATION = <CategoryEnum.FILM_ANIMATION: 1>
AUTOS_VEHICLES = <CategoryEnum.AUTOS_VEHICLES: 2>
MUSIC = <CategoryEnum.MUSIC: 10>
PETS_ANIMALS = <CategoryEnum.PETS_ANIMALS: 15>
SPORTS = <CategoryEnum.SPORTS: 17>
TRAVEL_EVENTS = <CategoryEnum.TRAVEL_EVENTS: 19>
GAMING = <CategoryEnum.GAMING: 20>
PEOPLE_BLOGS = <CategoryEnum.PEOPLE_BLOGS: 22>
COMEDY = <CategoryEnum.COMEDY: 23>
ENTERTAINMENT = <CategoryEnum.ENTERTAINMENT: 24>
NEWS_POLITICS = <CategoryEnum.NEWS_POLITICS: 25>
HOWTO_STYLE = <CategoryEnum.HOWTO_STYLE: 26>
EDUCATION = <CategoryEnum.EDUCATION: 27>
SCIENCE_TECH = <CategoryEnum.SCIENCE_TECH: 28>
NONPROFITS_ACTIVISM = <CategoryEnum.NONPROFITS_ACTIVISM: 29>
Inherited Members
enum.Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
class PrivacyEnum(builtins.str, enum.Enum):
11class PrivacyEnum(str, Enum):
12    PRIVATE = "PRIVATE"
13    UNLISTED = "UNLISTED"
14    PUBLIC = "PUBLIC"

An enumeration.

PRIVATE = <PrivacyEnum.PRIVATE: 'PRIVATE'>
UNLISTED = <PrivacyEnum.UNLISTED: 'UNLISTED'>
PUBLIC = <PrivacyEnum.PUBLIC: 'PUBLIC'>
Inherited Members
enum.Enum
name
value
builtins.str
encode
replace
split
rsplit
join
capitalize
casefold
title
center
count
expandtabs
find
partition
index
ljust
lower
lstrip
rfind
rindex
rjust
rstrip
rpartition
splitlines
strip
swapcase
translate
upper
startswith
endswith
removeprefix
removesuffix
isascii
islower
isupper
istitle
isspace
isdecimal
isdigit
isnumeric
isalpha
isalnum
isidentifier
isprintable
zfill
format
format_map
maketrans