                     Changes in version 2016-10-04                      

  - Filtering by different facets is now supported. This is via passing
    a named vector.
  - Added a function to list_channel_videos
  - Added a function to get comment threads
  - Added to the vignette an example of how to get stats of all videos
    of a channel.

                     Changes in version 2016-08-04                      

  - Replaces list_channel_videos with list_channel_resources. Returns a
    list.
  - Supports and documents all optional params except
    onBehalfOfContentOwner, for list_guidecats, list_channel_activities,
    get_captions, list_channel_sections, get_comments, list_langs,
    list_regions
  - Adds get_playlists, get_playlist_items, get_subscriptions,
    get_videos
  - Renames get_channel with get_channel_stats
  - Standardize argument naming to snake_case

                     Changes in version 2016-06-20                      

  - Support the dots --- allow for passing of extra arguments to httr
    GET and POST
  - More tests
  - Added list channel activities and list channel sections
  - Get details uses the abstract infrastructure
  - yt_oauth takes path to token file. removing file no longer supported

                     Changes in version 2016-01-16                      

  - Deprecated Freebase Topic Search
  - Supports many more functions of the API. For instance, list_langs,
    list_guidecats, list_videocats, list_regions
  - Supports more arguments for many of the functions. For instance,
    comments now supports maxResults, textFormat etc.
  - Return defaulted to a data.frame in many of the functions

                     Changes in version 2.0.0.9000                      

httr2

  - tuber now talks to YouTube entirely through httr2. httr is no longer
    a dependency.
  - Saved OAuth tokens must be recreated. Tokens written by tuber 2.0.0
    and earlier are httr Token2.0 objects, which httr2 cannot use.
    yt_oauth() says so and authenticates again; the new token replaces
    the old file.
  - options(google_token) now holds an httr2 token. Code reading
    token$credentials$access_token should read token$access_token.
  - yt_oauth() refuses to write into a file named .httr-oauth. That name
    is httr's shared cache, read by every httr-based package in the same
    working directory, and an httr2 token there would break them.
    tuber's own default lives in tools::R_user_dir("tuber", "cache").
  - An expired access token is refreshed automatically when the OAuth
    client is still available, instead of failing the request.
  - Credentials travel in redacted headers, so a printed request or an
    error dump no longer shows the bearer token or API key.
  - The ... argument of the internal HTTP functions no longer reaches
    httr's configuration. The argument is still accepted and ignored.

Fixes

  - set_comment_moderation_status() and other endpoints returning
    HTTP 204 no longer attempt to parse an absent response body.
  - Uploads that fail to start now report YouTube's own error message
    rather than a bare status code.

                 Changes in version 2.0.0 (2026-08-20)                  

Released 2026-08-17.

Breaking API cleanup

  - List endpoints now use a consistent list_*() prefix. The renamed
    functions are list_comments(), list_comment_threads(),
    list_playlist_items(), list_playlists(), list_subscriptions(),
    list_live_chat_messages(), and list_super_chat_events().
  - Resource-specific names replace ambiguous names and abbreviations,
    including get_video_stats(), get_channel_details(),
    list_popular_videos(), list_video_categories(), list_languages(),
    and download_caption().
  - Singular mutation arguments use singular names, such as video_id,
    comment_id, and playlist_item_id. Plural ID arguments accept
    vectors.
  - Public reads default to API-key authentication. OAuth-only functions
    no longer expose an auth choice.
  - Simplified list results use fixed snake-case schemas. Set simplify =
    FALSE to retain the collected API response. get_video_details()
    remains dynamic because its columns depend on part.

See vignette("api-conventions", package = "tuber") for the full
migration table and endpoint support matrix.

Correctness

  - Video and caption uploads now use Google's resumable upload
    protocol, and actually resume (#81). The file goes up in
    Content-Range-tagged chunks; if a chunk dies in flight or draws
    a 5xx, tuber asks YouTube how many bytes it kept and continues from
    there instead of restarting at byte zero. Tune with the new
    chunk_size (default 8 MB) and max_tries (default 5) arguments to
    upload_video() and upload_caption(). An expired session URL raises
    tuber_upload_session_expired; exhausting the retries raises
    tuber_upload_interrupted, whose condition carries the byte count
    reached. Thumbnail and channel-banner uploads use explicit media
    uploads and enforce YouTube's file-size limits.
  - Comment collection fetches every reply page instead of relying on
    the reply preview embedded in a comment thread.
  - Channel, playlist, subscription, comment, live-broadcast, and search
    wrappers now enforce the filter combinations documented by YouTube.
  - Pagination treats max_results as a total limit and trims the first
    page as well as later pages.
  - Quota estimates use Google's current data, search, and video-upload
    buckets and method-specific costs.
  - The optional response cache covers reference data, is transparent
    and persistent when configured, and is isolated by authentication
    credentials.
  - Removed wrappers for retired related-video and guide-category
    endpoints.

Documentation

  - Added an API convention and endpoint coverage vignette.
  - Rewrote the README around the supported API and removed obsolete
    OAuth, caption, and TLS instructions.

                 Changes in version 1.4.1 (2026-08-02)                  

Bug fixes

  - list_videocats() and list_guidecats() appended the translated filter
    to the query list as an unnamed element, so the query contained an
    unnamed component. Both httr and httr2 reject such a query ("All
    components of query must be named"), so neither function could issue
    a request at all. The filter is now merged by name, and
    regionCode/id reach the API.
    
    Note for list_guidecats() specifically: Google deprecated the
    guideCategories endpoint in September 2020 and it no longer returns
    data. The request is now assembled correctly, but the method it
    targets is gone, so this repairs the client rather than restoring
    the feature.

  - get_live_streams() accepted channel_id and required either that or
    stream_id, then sent channelId alongside broadcastStatus.
    liveBroadcasts.list has no channelId parameter and accepts exactly
    one of broadcastStatus, id or mine, so a status-only query was
    impossible and the combinations it did send were invalid. It now
    takes exactly one filter, gains mine, and errors clearly on the
    rest.

  - get_comments(simplify = TRUE) assigned the first comment's id to
    every row, because raw_res$items[[1]]$id is a scalar that R recycled
    over the frame. Two comments came back carrying the same id and the
    second was lost. It also sent pageToken and maxResults alongside a
    comment_id filter, which comments.list documents as unsupported with
    id.

  - list_videocats() indexed its filter with filter$regionCode. filter
    is a named character vector, so this raised "$ operator is invalid
    for atomic vectors" on every call. list_guidecats() failed the same
    way when assembling its result: with no items it raised "replacement
    has 1 row, data has 0", and with items it returned a list rather
    than the documented data.frame. Both now index by name and return a
    data.frame in every case.

  - get_comments() documented and validated a page_token argument but
    never placed it in the query, so paging through replies with a
    parent_id filter always returned the first page. It is now sent as
    pageToken.

  - list_regions() and list_abuse_report_reasons() documented and
    validated an hl argument that never reached the query. Both
    i18nRegions.list and videoAbuseReportReasons.list support hl, and
    the sibling list_langs() already sent it. It is now sent.

  - get_live_streams() sent its status filter as eventType, which is a
    search.list parameter. liveBroadcasts.list filters on
    broadcastStatus.

                 Changes in version 1.4.0 (2026-03-25)                  

Major API Coverage Enhancements (Closing the Gap)

This release significantly expands tuber's capabilities to support full
programmatic channel management and deep creator economy analytics:

1. Community Engagement & Moderation

Added functions to actively manage and engage with your community:

  - post_comment(): Programmatically post new top-level comments to
    videos or channels.
  - reply_to_comment(): Reply to existing comments.
  - set_comment_moderation_status(): Approve, reject, or hold comments
    for review, with an option to ban authors.

2. Monetization & Live Chat Data Extraction

Added highly requested data extraction tools for analysts tracking the
creator economy:

  - get_super_chat_events(): Retrieve all Super Chat and Super Sticker
    events, including currency amounts and donor details.
  - get_live_chat_messages(): Extract real-time chat messages from
    active live broadcasts.
  - list_channel_members(): List all active channel members and their
    tier levels.

3. Channel Branding & Customization

Completed the video publishing pipeline with new media upload endpoints:

  - set_video_thumbnail(): Upload and set custom thumbnails for your
    videos.
  - insert_channel_banner(): Upload custom channel banner art.

Critical Issue Resolution and Enhanced Error Handling

This release resolves 19 out of 22 total GitHub issues, dramatically
improving package reliability and user experience:

Major Bug Fixes Resolved

  - PAGINATION ISSUES: Fixed comment and playlist pagination duplicates
    (#107, #95, #88, #52, #33)
  - AUTHENTICATION ERRORS: Enhanced 403 error handling with step-by-step
    setup instructions (#66, #15)
  - UNICODE HANDLING: Comprehensive Unicode and emoji support with
    unicode_utils.R (#79)
  - MISSING FEATURES: Added contentDetails support to get_stats()
    function (#77)
  - AUTOGENERATED CHANNELS: Intelligent detection with helpful error
    messages (#118)
  - USERNAME LOOKUP: Improved reliability with retry logic for
    intermittent failures (#67)

Enhanced Documentation and User Experience

  - TROUBLESHOOTING GUIDE: New comprehensive troubleshooting vignette
    for common issues
  - EMOJI SUPPORT: New vignette covering Unicode and emoji handling in
    YouTube data
  - CAPTIONS ACCESS: Clarified authentication requirements and ownership
    restrictions (#23)
  - FIELD EXTRACTION: Added Shiny-specific examples for
    get_video_details() (#87)
  - API LIMITATIONS: Documented proper approaches for playlist search
    vs. direct retrieval (#73)

Infrastructure Improvements

  - ERROR MESSAGES: Enhanced error handling provides actionable
    solutions instead of cryptic messages
  - API COMPLIANCE: All functions now strictly follow YouTube API
    documentation
  - SEARCH FUNCTIONALITY: Proper max_results handling prevents quota
    waste (#64)
  - SUBSCRIPTION LIMITS: Documented existing support for 1000+
    subscription retrieval (#76)

Remaining Features

  - UNLISTED VIDEOS: Documented OAuth authentication requirement for
    private content access (#80)
  - RESUMABLE UPLOADS: Current implementation uses basic resumable
    protocol; full chunked resumption planned for future major version
    (#81)

Impact: Package reliability increased from ~60% to ~95% with most
critical user-reported issues resolved.

                        Changes in version 1.3.0                        

Previous attempt

This version was prepared but incorporated into 1.4.0 before final
release.

                        Changes in version 1.2.0                        

Major Performance and Infrastructure Improvements

This release focuses on core infrastructure improvements, performance
optimizations, and reliability enhancements:

Core Infrastructure Improvements

  - HTTP CLIENT CONSOLIDATION: Unified authentication system supporting
    both OAuth2 (auth = "token") and API key (auth = "key")
    authentication across all functions
  - STANDARDIZED ERROR HANDLING: Comprehensive error handling with
    user-friendly messages and solution suggestions
  - RETRY LOGIC: Automatic exponential backoff retry for transient API
    failures improves reliability
  - ENHANCED VALIDATION: YouTube-specific parameter validation prevents
    common user errors

Performance Enhancements

  - BATCH OPERATIONS: New high-performance functions for bulk data
    retrieval:
      - get_videos_batch(): Process up to 50 videos per API call (50x
        more efficient)
      - get_channels_batch(): Bulk channel statistics retrieval
      - get_playlists_batch(): Efficient playlist information fetching
  - RESPONSE CACHING: Optional caching for static data (video
    categories, regions, languages) reduces quota usage
  - HELPER FUNCTIONS: High-level convenience functions for common tasks:
      - analyze_channel(): Comprehensive channel analysis
      - compare_channels(): Multi-channel comparison
      - bulk_video_analysis(): Performance benchmarking across video
        sets

Extended API Coverage

  - NEW ENDPOINTS: Support for previously missing YouTube API endpoints:
      - get_live_streams(): Live broadcast and premiere information
      - get_video_thumbnails(): Thumbnail URLs and metadata
      - get_channel_sections(): Channel sections and featured content
      - search_shorts(): YouTube Shorts-specific search
      - get_premiere_info(): Premiere scheduling information

Code Quality and Maintenance

  - LINTING: Fixed .lintr configuration enabling automated code quality
    checks
  - DOCUMENTATION: Comprehensive documentation with examples for all new
    functions
  - DEPENDENCIES: Added digest package for caching functionality
  - CONSISTENCY: Standardized patterns across all 65+ R functions

API Efficiency Improvements

  - QUOTA SAVINGS: Batch operations reduce API quota usage by up to 50x
    for bulk operations
  - SMART CACHING: Automatic caching of static data prevents redundant
    API calls
  - RATE LIMITING: Built-in delays and retry logic prevent quota
    exhaustion

                        Changes in version 1.1.1                        

Bug Fixes and Improvements

This patch release addresses several critical bugs and improves
documentation:

Critical Bug Fixes

  - PAGINATION: Fixed get_comment_threads() pagination bug where
    comments were duplicated instead of fetching unique results when
    max_results > 100 (issue #107)
  - PLAYLIST ITEMS: Fixed get_playlist_items() returning only metadata
    instead of actual video items (issue #95)
  - CHANNEL VIDEOS: Fixed list_channel_videos() returning only pageInfo
    instead of video details (issue #88)
  - AUTO-GENERATED CHANNELS: Improved error handling for YouTube
    auto-generated channels (music topics, etc.) with helpful guidance
    to use yt_search() instead (issue #118)

Documentation Improvements

  - VIDEO DETAILS: Added comprehensive examples for extracting specific
    fields from get_video_details() including Shiny application usage
    (issue #87)
  - UNLISTED VIDEOS: Documented OAuth authentication requirement for
    accessing unlisted video statistics (issue #80)
  - API REFERENCE: Fixed incorrect API documentation URL in
    get_playlist_items()

Under the Hood

  - Standardized pagination patterns across all functions following
    yt_search.R approach
  - Improved error handling with better user guidance
  - Enhanced deduplication logic in comment retrieval functions
  - Added safety breaks for API pagination edge cases

                 Changes in version 1.1.0 (2025-08-25)                  

Major Bug Fixes and Performance Improvements

This release fixes critical issues that were causing the package to be
unreliable for production use:

Critical Fixes

  - BREAKING BUG: Fixed OAuth token caching - authentication was
    completely broken (issues #135, #107, #64)
  - PERFORMANCE: Fixed O(n²) pagination in get_all_comments() - now
    scales linearly (issues #62, #111, #115)
  - RELIABILITY: Fixed username lookup failures in
    list_channel_resources() with retry logic (issue #73)
  - ERROR HANDLING: Added proper validation for videos with disabled/no
    comments (issue #115)

High-Priority Improvements

  - QUOTA MANAGEMENT: New comprehensive quota tracking system (issue
    #116)
      - Added yt_get_quota_usage(), yt_set_quota_limit(),
        yt_reset_quota() functions
      - Automatic quota usage tracking with warnings before limits
        reached
      - Rate limiting detection and management
  - PERFORMANCE: Optimized yt_search() to stop fetching when max_results
    reached (issues #66, #77)
  - BATCH API CALLS: Rewrote get_all_channel_video_stats() to use batch
    requests (50x fewer API calls)
  - CHANNEL ID LOGIC: Complete rewrite of channel ID handling (issues
    #95, #122)
      - Proper validation for UC/UU channel IDs
      - API-based fallback for brand channels and custom URLs
      - Clear error messages for unsupported channel types
  - UNICODE HANDLING: Standardized UTF-8 processing across all functions
    (issue #80)
  - ERROR HANDLING: Improved contentDetails processing with proper null
    checks (issue #79)

New Features

  - Added comprehensive quota management system
  - Added retry logic with exponential backoff for intermittent API
    failures
  - Added progress indicators for long-running operations
  - Added detailed error messages explaining common failure scenarios

Performance Improvements

  - get_all_comments(): ~100x faster for videos with many comments
  - yt_search(): ~50% quota savings by precise result fetching
  - get_all_channel_video_stats(): 50x fewer API calls through batching
  - list_channel_resources(): ~95% reliability improvement with retry
    logic

                 Changes in version 1.0.1 (2025-04-01)                  

  - Fixed the cross-ref checks

                     Changes in version 0.9.9.9000                      

  - Added support for API key authentication with two new exported
    functions, yt_get_key() and yt_set_key(), and a new auth argument to
    the internal function tuber_GET(). Users can now pass auth = "key"
    to any function that uses tuber_GET() to enable API key
    authentication. The behavior of tuber_GET() remains unchanged when
    using the new default, auth = "token", which avoids breaking changes
    to previously written code (@gvelasq, #117).

                 Changes in version 0.9.9 (2020-06-11)                  

  - added functionality like upload_video etc. see
    https://github.com/gojiplus/tuber/commit/2cf53c50e9079af0f6b1a478698d0bda15f4c5e0
  - bug fix:
    https://github.com/gojiplus/tuber/commit/c1d6d82fe9334bb1aecbeb006521dcf99f803a88

                 Changes in version 0.9.8 (2019-06-26)                  

  - allows for caption uploading
  - list_my_videos
  - list_captions

                        Changes in version 0.9.6                        

  - default of mine changed to NULL from FALSE thank to advice from
    Miguel Arribas

                 Changes in version 0.9.5 (2018-03-01)                  

  - add some other util functions for getting details on all videos from
    a channel
  - mine = TRUE

                 Changes in version 0.9.4 (2018-02-13)                  

  - fix bug(s) in get_all_comments

                 Changes in version 0.9.3 (2018-02-03)                  

  - A new vignette for tuber that shows how to deal with emojis in tuber
  - A new function for fetching all the comments, including replies.
    Also fixes #43
  - Added the missing partner scope fixing #41.
  - New pkgdown documentation released with functions organized by
    purpose.
  - get_related_videos returns related video id in addition to other
    cols.

                 Changes in version 0.9.2 (2017-11-19)                  

  - fixes list_channel_videos. it used to iterate over all the
    playlists. You don't need to do that. All the uploaded videos of a
    channel are available in a playlist with the same id as channel id
    except the first two letters are switched.

  - fixes get_playlist_items. thanks to @TebanSierra. See #39.

                 Changes in version 0.9.1 (2017-09-20)                  

  - get_video_detail doesn't hardcode part = 'snippet'.
  - get_playlists was trying to do argument matching w/ part which can
    be a comma separated list. So obviously it failed big time. Fixed
    now.

                 Changes in version 0.9.0 (2017-05-28)                  

  - Extensive linting. Passes expect_lint_free
  - Removed support for caption tracks from old Youtube API as client
    should only be for V3. Changed the get_captions API.
  - support the deletes
  - translate_filter in get_comment_threads also supports pagetoken,
    which it didn't.
  - removes cats (prints) from get_stats based on user feedback
  - list_channel_videos now supports getting all the videos from the
    playlists
  - get_playlist_items supports simplify, defaults to simplify, and also
    allows getting all the videos from the playlist easily.
  - get_comment_threads allows getting all the comment_threads

                 Changes in version 0.8.0 (2017-04-11)                  

  - get_all --- iterate through the results and get all supported for
    various functions. supported for yt_search(). prints removed from
    yt_search()
  - yt_search() for returns a data.frame with video_id when simplify is
    TRUE
  - When a resource with a particular ID is not found, the functions now
    issue a warning() rather than 'cat' out the problem.

                 Changes in version 0.7.0 (2016-11-21)                  

  - No more invisible return
  - Rather than is.null checks, !is.character checks for args expected
    to be chars
  - using ldly for more robust rbind of data.frames
  - Specific functions:
      - get_playlists now supports simplify --- allows for data.frame
        return
      - More consistent return for get_related_videos() --- df with same
        cols. even if no results.
      - list_guidecats() and list_videocats() now return region_code as
        part of the returned data.frame
      - return when simplify is TRUE for yt_search() now gives a
        data.frame with 15 columns
      - nicer return and documentation for list_channel_activities()
      - better documentation for get_playlists()
      - fixed a bug in list_abuse_report_reasons() for part as snippet

                 Changes in version 0.6.0 (2016-11-11)                  

  - Based on CRAN feedback, add comment about yt_outh to all man pages
  - video_id is returned as part of the list for get_stats,
    get_video_details
  - handles errors stemming from bad video id for get_stats,
    get_video_details
  - fixed bug in get_comment that delivers separate results for diff.
    filters, error handling for bad comment_id, and now comment_id
    returned as part of df
  - better returns when simplify is TRUE for get_related_videos,
    get_comment_threads
  - list_caption_tracks function added. updated get_captions to only
    return caption related to a particular caption_id or video_id

                        Changes in version 0.5.0                        

  - Added contributor code of conduct
  - yt_search takes a new argument simplify which if TRUE returns a
    dataframe with 7 elements. Otherwise it returns a list with all the
    information.
