From 3ffc5a548f393ad67fa867f8079b5baf1213ff7e Mon Sep 17 00:00:00 2001 From: Joel Wachsler Date: Tue, 12 Jul 2022 23:39:06 +0000 Subject: [PATCH 01/47] Remove unused files --- qbittorrent-web-api-gen/src/parser/groups.txt | 5696 ------- .../src/parser/token_tree.txt | 13793 ---------------- 2 files changed, 19489 deletions(-) delete mode 100644 qbittorrent-web-api-gen/src/parser/groups.txt delete mode 100644 qbittorrent-web-api-gen/src/parser/token_tree.txt diff --git a/qbittorrent-web-api-gen/src/parser/groups.txt b/qbittorrent-web-api-gen/src/parser/groups.txt deleted file mode 100644 index 96d8e85..0000000 --- a/qbittorrent-web-api-gen/src/parser/groups.txt +++ /dev/null @@ -1,5696 +0,0 @@ -[ - ApiGroup { - name: "authentication", - methods: [ - ApiMethod { - name: "login", - description: Some( - "Example showing how to login and execute a command that requires authentication using `curl`:\n\n```sh\n$ curl -i --header 'Referer: http://localhost:8080' --data 'username=admin&password=adminadmin' http://localhost:8080/api/v2/auth/login\nHTTP/1.1 200 OK\nContent-Encoding:\nContent-Length: 3\nContent-Type: text/plain; charset=UTF-8\nSet-Cookie: SID=hBc7TxF76ERhvIw0jQQ4LZ7Z1jQUV0tQ; path=/\n$ curl http://localhost:8080/api/v2/torrents/info --cookie \"SID=hBc7TxF76ERhvIw0jQQ4LZ7Z1jQUV0tQ\"\n```\n\nNote: Set `Referer` or `Origin` header to the exact same domain and port as used in the HTTP query `Host` header.", - ), - parameters: Some( - [ - String( - TypeInfo { - name: "username", - is_optional: false, - is_list: false, - description: Some( - "Username used to access the WebUI", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "password", - is_optional: false, - is_list: false, - description: Some( - "Password used to access the WebUI", - ), - type_description: None, - }, - ), - ], - ), - return_type: None, - url: "login", - }, - ApiMethod { - name: "logout", - description: None, - parameters: None, - return_type: None, - url: "logout", - }, - ], - description: Some( - "All Authentication API methods are under \"auth\", e.g.: `/api/v2/auth/methodName`.\n\nqBittorrent uses cookie-based authentication.", - ), - url: "auth", - }, - ApiGroup { - name: "application", - methods: [ - ApiMethod { - name: "version", - description: None, - parameters: None, - return_type: None, - url: "version", - }, - ApiMethod { - name: "webapiVersion", - description: None, - parameters: None, - return_type: None, - url: "webapiVersion", - }, - ApiMethod { - name: "buildInfo", - description: None, - parameters: None, - return_type: Some( - ReturnType { - is_list: false, - parameters: [ - ReturnTypeParameter { - name: "qt", - description: "QT version", - return_type: String( - TypeInfo { - name: "qt", - is_optional: false, - is_list: false, - description: Some( - "QT version", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "libtorrent", - description: "libtorrent version", - return_type: String( - TypeInfo { - name: "libtorrent", - is_optional: false, - is_list: false, - description: Some( - "libtorrent version", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "boost", - description: "Boost version", - return_type: String( - TypeInfo { - name: "boost", - is_optional: false, - is_list: false, - description: Some( - "Boost version", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "openssl", - description: "OpenSSL version", - return_type: String( - TypeInfo { - name: "openssl", - is_optional: false, - is_list: false, - description: Some( - "OpenSSL version", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "bitness", - description: "Application bitness (e.g. 64-bit)", - return_type: Number( - TypeInfo { - name: "bitness", - is_optional: false, - is_list: false, - description: Some( - "Application bitness (e.g. 64-bit)", - ), - type_description: None, - }, - ), - }, - ], - }, - ), - url: "buildInfo", - }, - ApiMethod { - name: "shutdown", - description: None, - parameters: None, - return_type: None, - url: "shutdown", - }, - ApiMethod { - name: "preferences", - description: Some( - "Possible fields:\n\nPossible values of `scan_dirs`:\n\nPossible values of `scheduler_days`:\n\nPossible values of `encryption`:\n\nNB: the first options allows you to use both encrypted and unencrypted connections (this is the default); other options are mutually exclusive: e.g. by forcing encryption on you won't be able to use unencrypted connections and vice versa.\n\nPossible values of `proxy_type`:\n\nPossible values of `dyndns_service`:\n\nPossible values of `max_ratio_act`:\n\nPossible values of `bittorrent_protocol`:\n\nPossible values of `upload_choking_algorithm`:\n\nPossible values of `upload_slots_behavior`:\n\nPossible values of `utp_tcp_mixed_mode`:\n\nExample:\n\n```JSON\n{\n \"add_trackers\": \"\",\n \"add_trackers_enabled\": false,\n \"alt_dl_limit\": 10240,\n \"alt_up_limit\": 10240,\n \"alternative_webui_enabled\": false,\n \"alternative_webui_path\": \"/home/user/Documents/qbit-webui\",\n \"announce_ip\": \"\",\n \"announce_to_all_tiers\": true,\n \"announce_to_all_trackers\": false,\n \"anonymous_mode\": false,\n \"async_io_threads\": 4,\n \"auto_delete_mode\": 0,\n \"auto_tmm_enabled\": false,\n \"autorun_enabled\": false,\n \"autorun_program\": \"\",\n \"banned_IPs\": \"\",\n \"bittorrent_protocol\": 0,\n \"bypass_auth_subnet_whitelist\": \"\",\n \"bypass_auth_subnet_whitelist_enabled\": false,\n \"bypass_local_auth\": false,\n \"category_changed_tmm_enabled\": false,\n \"checking_memory_use\": 32,\n \"create_subfolder_enabled\": true,\n \"current_interface_address\": \"\",\n \"current_network_interface\": \"\",\n \"dht\": true,\n \"disk_cache\": -1,\n \"disk_cache_ttl\": 60,\n \"dl_limit\": 0,\n \"dont_count_slow_torrents\": false,\n \"dyndns_domain\": \"changeme.dyndns.org\",\n \"dyndns_enabled\": false,\n \"dyndns_password\": \"\",\n \"dyndns_service\": 0,\n \"dyndns_username\": \"\",\n \"embedded_tracker_port\": 9000,\n \"enable_coalesce_read_write\": false,\n \"enable_embedded_tracker\": false,\n \"enable_multi_connections_from_same_ip\": false,\n \"enable_os_cache\": true,\n \"enable_piece_extent_affinity\": false,\n \"enable_upload_suggestions\": false,\n \"encryption\": 0,\n \"export_dir\": \"/home/user/Downloads/all\",\n \"export_dir_fin\": \"/home/user/Downloads/completed\",\n \"file_pool_size\": 40,\n \"incomplete_files_ext\": false,\n \"ip_filter_enabled\": false,\n \"ip_filter_path\": \"\",\n \"ip_filter_trackers\": false,\n \"limit_lan_peers\": true,\n \"limit_tcp_overhead\": false,\n \"limit_utp_rate\": true,\n \"listen_port\": 58925,\n \"locale\": \"en\",\n \"lsd\": true,\n \"mail_notification_auth_enabled\": false,\n \"mail_notification_email\": \"\",\n \"mail_notification_enabled\": false,\n \"mail_notification_password\": \"\",\n \"mail_notification_sender\": \"qBittorrent_notification@example.com\",\n \"mail_notification_smtp\": \"smtp.changeme.com\",\n \"mail_notification_ssl_enabled\": false,\n \"mail_notification_username\": \"\",\n \"max_active_downloads\": 3,\n \"max_active_torrents\": 5,\n \"max_active_uploads\": 3,\n \"max_connec\": 500,\n \"max_connec_per_torrent\": 100,\n \"max_ratio\": -1,\n \"max_ratio_act\": 0,\n \"max_ratio_enabled\": false,\n \"max_seeding_time\": -1,\n \"max_seeding_time_enabled\": false,\n \"max_uploads\": -1,\n \"max_uploads_per_torrent\": -1,\n \"outgoing_ports_max\": 0,\n \"outgoing_ports_min\": 0,\n \"pex\": true,\n \"preallocate_all\": false,\n \"proxy_auth_enabled\": false,\n \"proxy_ip\": \"0.0.0.0\",\n \"proxy_password\": \"\",\n \"proxy_peer_connections\": false,\n \"proxy_port\": 8080,\n \"proxy_torrents_only\": false,\n \"proxy_type\": 0,\n \"proxy_username\": \"\",\n \"queueing_enabled\": false,\n \"random_port\": false,\n \"recheck_completed_torrents\": false,\n \"resolve_peer_countries\": true,\n \"rss_auto_downloading_enabled\":true,\n \"rss_download_repack_proper_episodes\":true,\n \"rss_max_articles_per_feed\":50,\n \"rss_processing_enabled\":true,\n \"rss_refresh_interval\":30,\n \"rss_smart_episode_filters\":\"s(\\\\d+)e(\\\\d+)\\n(\\\\d+)x(\\\\d+)\\n(\\\\d{4}[.\\\\-]\\\\d{1,2}[.\\\\-]\\\\d{1,2})\",\n \"save_path\": \"/home/user/Downloads/\",\n \"save_path_changed_tmm_enabled\": false,\n \"save_resume_data_interval\": 60,\n \"scan_dirs\":\n {\n \"/home/user/Downloads/incoming/games\": 0,\n \"/home/user/Downloads/incoming/movies\": 1,\n },\n \"schedule_from_hour\": 8,\n \"schedule_from_min\": 0,\n \"schedule_to_hour\": 20,\n \"schedule_to_min\": 0,\n \"scheduler_days\": 0,\n \"scheduler_enabled\": false,\n \"send_buffer_low_watermark\": 10,\n \"send_buffer_watermark\": 500,\n \"send_buffer_watermark_factor\": 50,\n \"slow_torrent_dl_rate_threshold\": 2,\n \"slow_torrent_inactive_timer\": 60,\n \"slow_torrent_ul_rate_threshold\": 2,\n \"socket_backlog_size\": 30,\n \"start_paused_enabled\": false,\n \"stop_tracker_timeout\": 1,\n \"temp_path\": \"/home/user/Downloads/temp\",\n \"temp_path_enabled\": false,\n \"torrent_changed_tmm_enabled\": true,\n \"up_limit\": 0,\n \"upload_choking_algorithm\": 1,\n \"upload_slots_behavior\": 0,\n \"upnp\": true,\n \"use_https\": false,\n \"utp_tcp_mixed_mode\": 0,\n \"web_ui_address\": \"*\",\n \"web_ui_ban_duration\": 3600,\n \"web_ui_clickjacking_protection_enabled\": true,\n \"web_ui_csrf_protection_enabled\": true,\n \"web_ui_custom_http_headers\": \"\",\n \"web_ui_domain_list\": \"*\",\n \"web_ui_host_header_validation_enabled\": true,\n \"web_ui_https_cert_path\": \"\",\n \"web_ui_https_key_path\": \"\",\n \"web_ui_max_auth_fail_count\": 5,\n \"web_ui_port\": 8080,\n \"web_ui_secure_cookie_enabled\": true,\n \"web_ui_session_timeout\": 3600,\n \"web_ui_upnp\": false,\n \"web_ui_use_custom_http_headers_enabled\": false,\n \"web_ui_username\": \"admin\"\n}\n```", - ), - parameters: None, - return_type: Some( - ReturnType { - is_list: false, - parameters: [ - ReturnTypeParameter { - name: "locale", - description: "Currently selected language (e.g. en_GB for English)", - return_type: String( - TypeInfo { - name: "locale", - is_optional: false, - is_list: false, - description: Some( - "Currently selected language (e.g. en_GB for English)", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "create_subfolder_enabled", - description: "True if a subfolder should be created when adding a torrent", - return_type: Bool( - TypeInfo { - name: "create_subfolder_enabled", - is_optional: false, - is_list: false, - description: Some( - "True if a subfolder should be created when adding a torrent", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "start_paused_enabled", - description: "True if torrents should be added in a Paused state", - return_type: Bool( - TypeInfo { - name: "start_paused_enabled", - is_optional: false, - is_list: false, - description: Some( - "True if torrents should be added in a Paused state", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "auto_delete_mode", - description: "TODO", - return_type: Number( - TypeInfo { - name: "auto_delete_mode", - is_optional: false, - is_list: false, - description: Some( - "TODO", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "preallocate_all", - description: "True if disk space should be pre-allocated for all files", - return_type: Bool( - TypeInfo { - name: "preallocate_all", - is_optional: false, - is_list: false, - description: Some( - "True if disk space should be pre-allocated for all files", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "incomplete_files_ext", - description: "True if \".!qB\" should be appended to incomplete files", - return_type: Bool( - TypeInfo { - name: "incomplete_files_ext", - is_optional: false, - is_list: false, - description: Some( - "True if \".!qB\" should be appended to incomplete files", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "auto_tmm_enabled", - description: "True if Automatic Torrent Management is enabled by default", - return_type: Bool( - TypeInfo { - name: "auto_tmm_enabled", - is_optional: false, - is_list: false, - description: Some( - "True if Automatic Torrent Management is enabled by default", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "torrent_changed_tmm_enabled", - description: "True if torrent should be relocated when its Category changes", - return_type: Bool( - TypeInfo { - name: "torrent_changed_tmm_enabled", - is_optional: false, - is_list: false, - description: Some( - "True if torrent should be relocated when its Category changes", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "save_path_changed_tmm_enabled", - description: "True if torrent should be relocated when the default save path changes", - return_type: Bool( - TypeInfo { - name: "save_path_changed_tmm_enabled", - is_optional: false, - is_list: false, - description: Some( - "True if torrent should be relocated when the default save path changes", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "category_changed_tmm_enabled", - description: "True if torrent should be relocated when its Category's save path changes", - return_type: Bool( - TypeInfo { - name: "category_changed_tmm_enabled", - is_optional: false, - is_list: false, - description: Some( - "True if torrent should be relocated when its Category's save path changes", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "save_path", - description: "Default save path for torrents, separated by slashes", - return_type: String( - TypeInfo { - name: "save_path", - is_optional: false, - is_list: false, - description: Some( - "Default save path for torrents, separated by slashes", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "temp_path_enabled", - description: "True if folder for incomplete torrents is enabled", - return_type: Bool( - TypeInfo { - name: "temp_path_enabled", - is_optional: false, - is_list: false, - description: Some( - "True if folder for incomplete torrents is enabled", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "temp_path", - description: "Path for incomplete torrents, separated by slashes", - return_type: String( - TypeInfo { - name: "temp_path", - is_optional: false, - is_list: false, - description: Some( - "Path for incomplete torrents, separated by slashes", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "scan_dirs", - description: "Property: directory to watch for torrent files, value: where torrents loaded from this directory should be downloaded to (see list of possible values below). Slashes are used as path separators; multiple key/value pairs can be specified", - return_type: Object( - TypeInfo { - name: "scan_dirs", - is_optional: false, - is_list: false, - description: Some( - "Property: directory to watch for torrent files, value: where torrents loaded from this directory should be downloaded to (see list of possible values below). Slashes are used as path separators; multiple key/value pairs can be specified", - ), - type_description: Some( - TypeDescription { - values: [ - TypeDescriptions { - value: "0", - description: "Download to the monitored folder", - }, - TypeDescriptions { - value: "1", - description: "Download to the default save path", - }, - TypeDescriptions { - value: "\"/path/to/download/to\"", - description: "Download to this path", - }, - ], - }, - ), - }, - ), - }, - ReturnTypeParameter { - name: "export_dir", - description: "Path to directory to copy .torrent files to. Slashes are used as path separators", - return_type: String( - TypeInfo { - name: "export_dir", - is_optional: false, - is_list: false, - description: Some( - "Path to directory to copy .torrent files to. Slashes are used as path separators", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "export_dir_fin", - description: "Path to directory to copy .torrent files of completed downloads to. Slashes are used as path separators", - return_type: String( - TypeInfo { - name: "export_dir_fin", - is_optional: false, - is_list: false, - description: Some( - "Path to directory to copy .torrent files of completed downloads to. Slashes are used as path separators", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "mail_notification_enabled", - description: "True if e-mail notification should be enabled", - return_type: Bool( - TypeInfo { - name: "mail_notification_enabled", - is_optional: false, - is_list: false, - description: Some( - "True if e-mail notification should be enabled", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "mail_notification_sender", - description: "e-mail where notifications should originate from", - return_type: String( - TypeInfo { - name: "mail_notification_sender", - is_optional: false, - is_list: false, - description: Some( - "e-mail where notifications should originate from", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "mail_notification_email", - description: "e-mail to send notifications to", - return_type: String( - TypeInfo { - name: "mail_notification_email", - is_optional: false, - is_list: false, - description: Some( - "e-mail to send notifications to", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "mail_notification_smtp", - description: "smtp server for e-mail notifications", - return_type: String( - TypeInfo { - name: "mail_notification_smtp", - is_optional: false, - is_list: false, - description: Some( - "smtp server for e-mail notifications", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "mail_notification_ssl_enabled", - description: "True if smtp server requires SSL connection", - return_type: Bool( - TypeInfo { - name: "mail_notification_ssl_enabled", - is_optional: false, - is_list: false, - description: Some( - "True if smtp server requires SSL connection", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "mail_notification_auth_enabled", - description: "True if smtp server requires authentication", - return_type: Bool( - TypeInfo { - name: "mail_notification_auth_enabled", - is_optional: false, - is_list: false, - description: Some( - "True if smtp server requires authentication", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "mail_notification_username", - description: "Username for smtp authentication", - return_type: String( - TypeInfo { - name: "mail_notification_username", - is_optional: false, - is_list: false, - description: Some( - "Username for smtp authentication", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "mail_notification_password", - description: "Password for smtp authentication", - return_type: String( - TypeInfo { - name: "mail_notification_password", - is_optional: false, - is_list: false, - description: Some( - "Password for smtp authentication", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "autorun_enabled", - description: "True if external program should be run after torrent has finished downloading", - return_type: Bool( - TypeInfo { - name: "autorun_enabled", - is_optional: false, - is_list: false, - description: Some( - "True if external program should be run after torrent has finished downloading", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "autorun_program", - description: "Program path/name/arguments to run if autorun_enabled is enabled; path is separated by slashes; you can use %f and %n arguments, which will be expanded by qBittorent as path_to_torrent_file and torrent_name (from the GUI; not the .torrent file name) respectively", - return_type: String( - TypeInfo { - name: "autorun_program", - is_optional: false, - is_list: false, - description: Some( - "Program path/name/arguments to run if autorun_enabled is enabled; path is separated by slashes; you can use %f and %n arguments, which will be expanded by qBittorent as path_to_torrent_file and torrent_name (from the GUI; not the .torrent file name) respectively", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "queueing_enabled", - description: "True if torrent queuing is enabled", - return_type: Bool( - TypeInfo { - name: "queueing_enabled", - is_optional: false, - is_list: false, - description: Some( - "True if torrent queuing is enabled", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "max_active_downloads", - description: "Maximum number of active simultaneous downloads", - return_type: Number( - TypeInfo { - name: "max_active_downloads", - is_optional: false, - is_list: false, - description: Some( - "Maximum number of active simultaneous downloads", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "max_active_torrents", - description: "Maximum number of active simultaneous downloads and uploads", - return_type: Number( - TypeInfo { - name: "max_active_torrents", - is_optional: false, - is_list: false, - description: Some( - "Maximum number of active simultaneous downloads and uploads", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "max_active_uploads", - description: "Maximum number of active simultaneous uploads", - return_type: Number( - TypeInfo { - name: "max_active_uploads", - is_optional: false, - is_list: false, - description: Some( - "Maximum number of active simultaneous uploads", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "dont_count_slow_torrents", - description: "If true torrents w/o any activity (stalled ones) will not be counted towards max_active_* limits; see [dont_count_slow_torrents](https://www.libtorrent.org/reference-Settings.html#dont_count_slow_torrents) for more information", - return_type: Bool( - TypeInfo { - name: "dont_count_slow_torrents", - is_optional: false, - is_list: false, - description: Some( - "If true torrents w/o any activity (stalled ones) will not be counted towards max_active_* limits; see [dont_count_slow_torrents](https://www.libtorrent.org/reference-Settings.html#dont_count_slow_torrents) for more information", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "slow_torrent_dl_rate_threshold", - description: "Download rate in KiB/s for a torrent to be considered \"slow\"", - return_type: Number( - TypeInfo { - name: "slow_torrent_dl_rate_threshold", - is_optional: false, - is_list: false, - description: Some( - "Download rate in KiB/s for a torrent to be considered \"slow\"", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "slow_torrent_ul_rate_threshold", - description: "Upload rate in KiB/s for a torrent to be considered \"slow\"", - return_type: Number( - TypeInfo { - name: "slow_torrent_ul_rate_threshold", - is_optional: false, - is_list: false, - description: Some( - "Upload rate in KiB/s for a torrent to be considered \"slow\"", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "slow_torrent_inactive_timer", - description: "Seconds a torrent should be inactive before considered \"slow\"", - return_type: Number( - TypeInfo { - name: "slow_torrent_inactive_timer", - is_optional: false, - is_list: false, - description: Some( - "Seconds a torrent should be inactive before considered \"slow\"", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "max_ratio_enabled", - description: "True if share ratio limit is enabled", - return_type: Bool( - TypeInfo { - name: "max_ratio_enabled", - is_optional: false, - is_list: false, - description: Some( - "True if share ratio limit is enabled", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "max_ratio", - description: "Get the global share ratio limit", - return_type: Float( - TypeInfo { - name: "max_ratio", - is_optional: false, - is_list: false, - description: Some( - "Get the global share ratio limit", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "max_ratio_act", - description: "Action performed when a torrent reaches the maximum share ratio. See list of possible values here below.", - return_type: Number( - TypeInfo { - name: "max_ratio_act", - is_optional: false, - is_list: false, - description: Some( - "Action performed when a torrent reaches the maximum share ratio. See list of possible values here below.", - ), - type_description: Some( - TypeDescription { - values: [ - TypeDescriptions { - value: "0", - description: "Pause torrent", - }, - TypeDescriptions { - value: "1", - description: "Remove torrent", - }, - ], - }, - ), - }, - ), - }, - ReturnTypeParameter { - name: "listen_port", - description: "Port for incoming connections", - return_type: Number( - TypeInfo { - name: "listen_port", - is_optional: false, - is_list: false, - description: Some( - "Port for incoming connections", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "upnp", - description: "True if UPnP/NAT-PMP is enabled", - return_type: Bool( - TypeInfo { - name: "upnp", - is_optional: false, - is_list: false, - description: Some( - "True if UPnP/NAT-PMP is enabled", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "random_port", - description: "True if the port is randomly selected", - return_type: Bool( - TypeInfo { - name: "random_port", - is_optional: false, - is_list: false, - description: Some( - "True if the port is randomly selected", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "dl_limit", - description: "Global download speed limit in KiB/s; -1 means no limit is applied", - return_type: Number( - TypeInfo { - name: "dl_limit", - is_optional: false, - is_list: false, - description: Some( - "Global download speed limit in KiB/s; -1 means no limit is applied", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "up_limit", - description: "Global upload speed limit in KiB/s; -1 means no limit is applied", - return_type: Number( - TypeInfo { - name: "up_limit", - is_optional: false, - is_list: false, - description: Some( - "Global upload speed limit in KiB/s; -1 means no limit is applied", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "max_connec", - description: "Maximum global number of simultaneous connections", - return_type: Number( - TypeInfo { - name: "max_connec", - is_optional: false, - is_list: false, - description: Some( - "Maximum global number of simultaneous connections", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "max_connec_per_torrent", - description: "Maximum number of simultaneous connections per torrent", - return_type: Number( - TypeInfo { - name: "max_connec_per_torrent", - is_optional: false, - is_list: false, - description: Some( - "Maximum number of simultaneous connections per torrent", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "max_uploads", - description: "Maximum number of upload slots", - return_type: Number( - TypeInfo { - name: "max_uploads", - is_optional: false, - is_list: false, - description: Some( - "Maximum number of upload slots", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "max_uploads_per_torrent", - description: "Maximum number of upload slots per torrent", - return_type: Number( - TypeInfo { - name: "max_uploads_per_torrent", - is_optional: false, - is_list: false, - description: Some( - "Maximum number of upload slots per torrent", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "stop_tracker_timeout", - description: "Timeout in seconds for a stopped announce request to trackers", - return_type: Number( - TypeInfo { - name: "stop_tracker_timeout", - is_optional: false, - is_list: false, - description: Some( - "Timeout in seconds for a stopped announce request to trackers", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "enable_piece_extent_affinity", - description: "True if the advanced libtorrent option piece_extent_affinity is enabled", - return_type: Bool( - TypeInfo { - name: "enable_piece_extent_affinity", - is_optional: false, - is_list: false, - description: Some( - "True if the advanced libtorrent option piece_extent_affinity is enabled", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "bittorrent_protocol", - description: "Bittorrent Protocol to use (see list of possible values below)", - return_type: Number( - TypeInfo { - name: "bittorrent_protocol", - is_optional: false, - is_list: false, - description: Some( - "Bittorrent Protocol to use (see list of possible values below)", - ), - type_description: Some( - TypeDescription { - values: [ - TypeDescriptions { - value: "0", - description: "TCP and μTP", - }, - TypeDescriptions { - value: "1", - description: "TCP", - }, - TypeDescriptions { - value: "2", - description: "μTP", - }, - ], - }, - ), - }, - ), - }, - ReturnTypeParameter { - name: "limit_utp_rate", - description: "True if [du]l_limit should be applied to uTP connections; this option is only available in qBittorent built against libtorrent version 0.16.X and higher", - return_type: Bool( - TypeInfo { - name: "limit_utp_rate", - is_optional: false, - is_list: false, - description: Some( - "True if [du]l_limit should be applied to uTP connections; this option is only available in qBittorent built against libtorrent version 0.16.X and higher", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "limit_tcp_overhead", - description: "True if [du]l_limit should be applied to estimated TCP overhead (service data: e.g. packet headers)", - return_type: Bool( - TypeInfo { - name: "limit_tcp_overhead", - is_optional: false, - is_list: false, - description: Some( - "True if [du]l_limit should be applied to estimated TCP overhead (service data: e.g. packet headers)", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "limit_lan_peers", - description: "True if [du]l_limit should be applied to peers on the LAN", - return_type: Bool( - TypeInfo { - name: "limit_lan_peers", - is_optional: false, - is_list: false, - description: Some( - "True if [du]l_limit should be applied to peers on the LAN", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "alt_dl_limit", - description: "Alternative global download speed limit in KiB/s", - return_type: Number( - TypeInfo { - name: "alt_dl_limit", - is_optional: false, - is_list: false, - description: Some( - "Alternative global download speed limit in KiB/s", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "alt_up_limit", - description: "Alternative global upload speed limit in KiB/s", - return_type: Number( - TypeInfo { - name: "alt_up_limit", - is_optional: false, - is_list: false, - description: Some( - "Alternative global upload speed limit in KiB/s", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "scheduler_enabled", - description: "True if alternative limits should be applied according to schedule", - return_type: Bool( - TypeInfo { - name: "scheduler_enabled", - is_optional: false, - is_list: false, - description: Some( - "True if alternative limits should be applied according to schedule", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "schedule_from_hour", - description: "Scheduler starting hour", - return_type: Number( - TypeInfo { - name: "schedule_from_hour", - is_optional: false, - is_list: false, - description: Some( - "Scheduler starting hour", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "schedule_from_min", - description: "Scheduler starting minute", - return_type: Number( - TypeInfo { - name: "schedule_from_min", - is_optional: false, - is_list: false, - description: Some( - "Scheduler starting minute", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "schedule_to_hour", - description: "Scheduler ending hour", - return_type: Number( - TypeInfo { - name: "schedule_to_hour", - is_optional: false, - is_list: false, - description: Some( - "Scheduler ending hour", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "schedule_to_min", - description: "Scheduler ending minute", - return_type: Number( - TypeInfo { - name: "schedule_to_min", - is_optional: false, - is_list: false, - description: Some( - "Scheduler ending minute", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "scheduler_days", - description: "Scheduler days. See possible values here below", - return_type: Number( - TypeInfo { - name: "scheduler_days", - is_optional: false, - is_list: false, - description: Some( - "Scheduler days. See possible values here below", - ), - type_description: Some( - TypeDescription { - values: [ - TypeDescriptions { - value: "0", - description: "Every day", - }, - TypeDescriptions { - value: "1", - description: "Every weekday", - }, - TypeDescriptions { - value: "2", - description: "Every weekend", - }, - TypeDescriptions { - value: "3", - description: "Every Monday", - }, - TypeDescriptions { - value: "4", - description: "Every Tuesday", - }, - TypeDescriptions { - value: "5", - description: "Every Wednesday", - }, - TypeDescriptions { - value: "6", - description: "Every Thursday", - }, - TypeDescriptions { - value: "7", - description: "Every Friday", - }, - TypeDescriptions { - value: "8", - description: "Every Saturday", - }, - TypeDescriptions { - value: "9", - description: "Every Sunday", - }, - ], - }, - ), - }, - ), - }, - ReturnTypeParameter { - name: "dht", - description: "True if DHT is enabled", - return_type: Bool( - TypeInfo { - name: "dht", - is_optional: false, - is_list: false, - description: Some( - "True if DHT is enabled", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "pex", - description: "True if PeX is enabled", - return_type: Bool( - TypeInfo { - name: "pex", - is_optional: false, - is_list: false, - description: Some( - "True if PeX is enabled", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "lsd", - description: "True if LSD is enabled", - return_type: Bool( - TypeInfo { - name: "lsd", - is_optional: false, - is_list: false, - description: Some( - "True if LSD is enabled", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "encryption", - description: "See list of possible values here below", - return_type: Number( - TypeInfo { - name: "encryption", - is_optional: false, - is_list: false, - description: Some( - "See list of possible values here below", - ), - type_description: Some( - TypeDescription { - values: [ - TypeDescriptions { - value: "0", - description: "Prefer encryption", - }, - TypeDescriptions { - value: "1", - description: "Force encryption on", - }, - TypeDescriptions { - value: "2", - description: "Force encryption off", - }, - ], - }, - ), - }, - ), - }, - ReturnTypeParameter { - name: "anonymous_mode", - description: "If true anonymous mode will be enabled; read more [here](Anonymous-Mode); this option is only available in qBittorent built against libtorrent version 0.16.X and higher", - return_type: Bool( - TypeInfo { - name: "anonymous_mode", - is_optional: false, - is_list: false, - description: Some( - "If true anonymous mode will be enabled; read more [here](Anonymous-Mode); this option is only available in qBittorent built against libtorrent version 0.16.X and higher", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "proxy_type", - description: "See list of possible values here below", - return_type: Number( - TypeInfo { - name: "proxy_type", - is_optional: false, - is_list: false, - description: Some( - "See list of possible values here below", - ), - type_description: Some( - TypeDescription { - values: [ - TypeDescriptions { - value: "-1", - description: "Proxy is disabled", - }, - TypeDescriptions { - value: "1", - description: "HTTP proxy without authentication", - }, - TypeDescriptions { - value: "2", - description: "SOCKS5 proxy without authentication", - }, - TypeDescriptions { - value: "3", - description: "HTTP proxy with authentication", - }, - TypeDescriptions { - value: "4", - description: "SOCKS5 proxy with authentication", - }, - TypeDescriptions { - value: "5", - description: "SOCKS4 proxy without authentication", - }, - ], - }, - ), - }, - ), - }, - ReturnTypeParameter { - name: "proxy_ip", - description: "Proxy IP address or domain name", - return_type: String( - TypeInfo { - name: "proxy_ip", - is_optional: false, - is_list: false, - description: Some( - "Proxy IP address or domain name", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "proxy_port", - description: "Proxy port", - return_type: Number( - TypeInfo { - name: "proxy_port", - is_optional: false, - is_list: false, - description: Some( - "Proxy port", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "proxy_peer_connections", - description: "True if peer and web seed connections should be proxified; this option will have any effect only in qBittorent built against libtorrent version 0.16.X and higher", - return_type: Bool( - TypeInfo { - name: "proxy_peer_connections", - is_optional: false, - is_list: false, - description: Some( - "True if peer and web seed connections should be proxified; this option will have any effect only in qBittorent built against libtorrent version 0.16.X and higher", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "proxy_auth_enabled", - description: "True proxy requires authentication; doesn't apply to SOCKS4 proxies", - return_type: Bool( - TypeInfo { - name: "proxy_auth_enabled", - is_optional: false, - is_list: false, - description: Some( - "True proxy requires authentication; doesn't apply to SOCKS4 proxies", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "proxy_username", - description: "Username for proxy authentication", - return_type: String( - TypeInfo { - name: "proxy_username", - is_optional: false, - is_list: false, - description: Some( - "Username for proxy authentication", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "proxy_password", - description: "Password for proxy authentication", - return_type: String( - TypeInfo { - name: "proxy_password", - is_optional: false, - is_list: false, - description: Some( - "Password for proxy authentication", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "proxy_torrents_only", - description: "True if proxy is only used for torrents", - return_type: Bool( - TypeInfo { - name: "proxy_torrents_only", - is_optional: false, - is_list: false, - description: Some( - "True if proxy is only used for torrents", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "ip_filter_enabled", - description: "True if external IP filter should be enabled", - return_type: Bool( - TypeInfo { - name: "ip_filter_enabled", - is_optional: false, - is_list: false, - description: Some( - "True if external IP filter should be enabled", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "ip_filter_path", - description: "Path to IP filter file (.dat, .p2p, .p2b files are supported); path is separated by slashes", - return_type: String( - TypeInfo { - name: "ip_filter_path", - is_optional: false, - is_list: false, - description: Some( - "Path to IP filter file (.dat, .p2p, .p2b files are supported); path is separated by slashes", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "ip_filter_trackers", - description: "True if IP filters are applied to trackers", - return_type: Bool( - TypeInfo { - name: "ip_filter_trackers", - is_optional: false, - is_list: false, - description: Some( - "True if IP filters are applied to trackers", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "web_ui_domain_list", - description: "Comma-separated list of domains to accept when performing Host header validation", - return_type: String( - TypeInfo { - name: "web_ui_domain_list", - is_optional: false, - is_list: false, - description: Some( - "Comma-separated list of domains to accept when performing Host header validation", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "web_ui_address", - description: "IP address to use for the WebUI", - return_type: String( - TypeInfo { - name: "web_ui_address", - is_optional: false, - is_list: false, - description: Some( - "IP address to use for the WebUI", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "web_ui_port", - description: "WebUI port", - return_type: Number( - TypeInfo { - name: "web_ui_port", - is_optional: false, - is_list: false, - description: Some( - "WebUI port", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "web_ui_upnp", - description: "True if UPnP is used for the WebUI port", - return_type: Bool( - TypeInfo { - name: "web_ui_upnp", - is_optional: false, - is_list: false, - description: Some( - "True if UPnP is used for the WebUI port", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "web_ui_username", - description: "WebUI username", - return_type: String( - TypeInfo { - name: "web_ui_username", - is_optional: false, - is_list: false, - description: Some( - "WebUI username", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "web_ui_password", - description: "For API ≥ v2.3.0: Plaintext WebUI password, not readable, write-only. For API < v2.3.0: MD5 hash of WebUI password, hash is generated from the following string: username:Web UI Access:plain_text_web_ui_password", - return_type: String( - TypeInfo { - name: "web_ui_password", - is_optional: false, - is_list: false, - description: Some( - "For API ≥ v2.3.0: Plaintext WebUI password, not readable, write-only. For API < v2.3.0: MD5 hash of WebUI password, hash is generated from the following string: username:Web UI Access:plain_text_web_ui_password", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "web_ui_csrf_protection_enabled", - description: "True if WebUI CSRF protection is enabled", - return_type: Bool( - TypeInfo { - name: "web_ui_csrf_protection_enabled", - is_optional: false, - is_list: false, - description: Some( - "True if WebUI CSRF protection is enabled", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "web_ui_clickjacking_protection_enabled", - description: "True if WebUI clickjacking protection is enabled", - return_type: Bool( - TypeInfo { - name: "web_ui_clickjacking_protection_enabled", - is_optional: false, - is_list: false, - description: Some( - "True if WebUI clickjacking protection is enabled", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "web_ui_secure_cookie_enabled", - description: "True if WebUI cookie Secure flag is enabled", - return_type: Bool( - TypeInfo { - name: "web_ui_secure_cookie_enabled", - is_optional: false, - is_list: false, - description: Some( - "True if WebUI cookie Secure flag is enabled", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "web_ui_max_auth_fail_count", - description: "Maximum number of authentication failures before WebUI access ban", - return_type: Number( - TypeInfo { - name: "web_ui_max_auth_fail_count", - is_optional: false, - is_list: false, - description: Some( - "Maximum number of authentication failures before WebUI access ban", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "web_ui_ban_duration", - description: "WebUI access ban duration in seconds", - return_type: Number( - TypeInfo { - name: "web_ui_ban_duration", - is_optional: false, - is_list: false, - description: Some( - "WebUI access ban duration in seconds", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "web_ui_session_timeout", - description: "Seconds until WebUI is automatically signed off", - return_type: Number( - TypeInfo { - name: "web_ui_session_timeout", - is_optional: false, - is_list: false, - description: Some( - "Seconds until WebUI is automatically signed off", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "web_ui_host_header_validation_enabled", - description: "True if WebUI host header validation is enabled", - return_type: Bool( - TypeInfo { - name: "web_ui_host_header_validation_enabled", - is_optional: false, - is_list: false, - description: Some( - "True if WebUI host header validation is enabled", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "bypass_local_auth", - description: "True if authentication challenge for loopback address (127.0.0.1) should be disabled", - return_type: Bool( - TypeInfo { - name: "bypass_local_auth", - is_optional: false, - is_list: false, - description: Some( - "True if authentication challenge for loopback address (127.0.0.1) should be disabled", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "bypass_auth_subnet_whitelist_enabled", - description: "True if webui authentication should be bypassed for clients whose ip resides within (at least) one of the subnets on the whitelist", - return_type: Bool( - TypeInfo { - name: "bypass_auth_subnet_whitelist_enabled", - is_optional: false, - is_list: false, - description: Some( - "True if webui authentication should be bypassed for clients whose ip resides within (at least) one of the subnets on the whitelist", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "bypass_auth_subnet_whitelist", - description: "(White)list of ipv4/ipv6 subnets for which webui authentication should be bypassed; list entries are separated by commas", - return_type: String( - TypeInfo { - name: "bypass_auth_subnet_whitelist", - is_optional: false, - is_list: false, - description: Some( - "(White)list of ipv4/ipv6 subnets for which webui authentication should be bypassed; list entries are separated by commas", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "alternative_webui_enabled", - description: "True if an alternative WebUI should be used", - return_type: Bool( - TypeInfo { - name: "alternative_webui_enabled", - is_optional: false, - is_list: false, - description: Some( - "True if an alternative WebUI should be used", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "alternative_webui_path", - description: "File path to the alternative WebUI", - return_type: String( - TypeInfo { - name: "alternative_webui_path", - is_optional: false, - is_list: false, - description: Some( - "File path to the alternative WebUI", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "use_https", - description: "True if WebUI HTTPS access is enabled", - return_type: Bool( - TypeInfo { - name: "use_https", - is_optional: false, - is_list: false, - description: Some( - "True if WebUI HTTPS access is enabled", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "ssl_key", - description: "For API < v2.0.1: SSL keyfile contents (this is a not a path)", - return_type: String( - TypeInfo { - name: "ssl_key", - is_optional: false, - is_list: false, - description: Some( - "For API < v2.0.1: SSL keyfile contents (this is a not a path)", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "ssl_cert", - description: "For API < v2.0.1: SSL certificate contents (this is a not a path)", - return_type: String( - TypeInfo { - name: "ssl_cert", - is_optional: false, - is_list: false, - description: Some( - "For API < v2.0.1: SSL certificate contents (this is a not a path)", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "web_ui_https_key_path", - description: "For API ≥ v2.0.1: Path to SSL keyfile", - return_type: String( - TypeInfo { - name: "web_ui_https_key_path", - is_optional: false, - is_list: false, - description: Some( - "For API ≥ v2.0.1: Path to SSL keyfile", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "web_ui_https_cert_path", - description: "For API ≥ v2.0.1: Path to SSL certificate", - return_type: String( - TypeInfo { - name: "web_ui_https_cert_path", - is_optional: false, - is_list: false, - description: Some( - "For API ≥ v2.0.1: Path to SSL certificate", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "dyndns_enabled", - description: "True if server DNS should be updated dynamically", - return_type: Bool( - TypeInfo { - name: "dyndns_enabled", - is_optional: false, - is_list: false, - description: Some( - "True if server DNS should be updated dynamically", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "dyndns_service", - description: "See list of possible values here below", - return_type: Number( - TypeInfo { - name: "dyndns_service", - is_optional: false, - is_list: false, - description: Some( - "See list of possible values here below", - ), - type_description: Some( - TypeDescription { - values: [ - TypeDescriptions { - value: "0", - description: "Use DyDNS", - }, - TypeDescriptions { - value: "1", - description: "Use NOIP", - }, - ], - }, - ), - }, - ), - }, - ReturnTypeParameter { - name: "dyndns_username", - description: "Username for DDNS service", - return_type: String( - TypeInfo { - name: "dyndns_username", - is_optional: false, - is_list: false, - description: Some( - "Username for DDNS service", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "dyndns_password", - description: "Password for DDNS service", - return_type: String( - TypeInfo { - name: "dyndns_password", - is_optional: false, - is_list: false, - description: Some( - "Password for DDNS service", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "dyndns_domain", - description: "Your DDNS domain name", - return_type: String( - TypeInfo { - name: "dyndns_domain", - is_optional: false, - is_list: false, - description: Some( - "Your DDNS domain name", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "rss_refresh_interval", - description: "RSS refresh interval", - return_type: Number( - TypeInfo { - name: "rss_refresh_interval", - is_optional: false, - is_list: false, - description: Some( - "RSS refresh interval", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "rss_max_articles_per_feed", - description: "Max stored articles per RSS feed", - return_type: Number( - TypeInfo { - name: "rss_max_articles_per_feed", - is_optional: false, - is_list: false, - description: Some( - "Max stored articles per RSS feed", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "rss_processing_enabled", - description: "Enable processing of RSS feeds", - return_type: Bool( - TypeInfo { - name: "rss_processing_enabled", - is_optional: false, - is_list: false, - description: Some( - "Enable processing of RSS feeds", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "rss_auto_downloading_enabled", - description: "Enable auto-downloading of torrents from the RSS feeds", - return_type: Bool( - TypeInfo { - name: "rss_auto_downloading_enabled", - is_optional: false, - is_list: false, - description: Some( - "Enable auto-downloading of torrents from the RSS feeds", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "rss_download_repack_proper_episodes", - description: "For API ≥ v2.5.1: Enable downloading of repack/proper Episodes", - return_type: Bool( - TypeInfo { - name: "rss_download_repack_proper_episodes", - is_optional: false, - is_list: false, - description: Some( - "For API ≥ v2.5.1: Enable downloading of repack/proper Episodes", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "rss_smart_episode_filters", - description: "For API ≥ v2.5.1: List of RSS Smart Episode Filters", - return_type: String( - TypeInfo { - name: "rss_smart_episode_filters", - is_optional: false, - is_list: false, - description: Some( - "For API ≥ v2.5.1: List of RSS Smart Episode Filters", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "add_trackers_enabled", - description: "Enable automatic adding of trackers to new torrents", - return_type: Bool( - TypeInfo { - name: "add_trackers_enabled", - is_optional: false, - is_list: false, - description: Some( - "Enable automatic adding of trackers to new torrents", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "add_trackers", - description: "List of trackers to add to new torrent", - return_type: String( - TypeInfo { - name: "add_trackers", - is_optional: false, - is_list: false, - description: Some( - "List of trackers to add to new torrent", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "web_ui_use_custom_http_headers_enabled", - description: "For API ≥ v2.5.1: Enable custom http headers", - return_type: Bool( - TypeInfo { - name: "web_ui_use_custom_http_headers_enabled", - is_optional: false, - is_list: false, - description: Some( - "For API ≥ v2.5.1: Enable custom http headers", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "web_ui_custom_http_headers", - description: "For API ≥ v2.5.1: List of custom http headers", - return_type: String( - TypeInfo { - name: "web_ui_custom_http_headers", - is_optional: false, - is_list: false, - description: Some( - "For API ≥ v2.5.1: List of custom http headers", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "max_seeding_time_enabled", - description: "True enables max seeding time", - return_type: Bool( - TypeInfo { - name: "max_seeding_time_enabled", - is_optional: false, - is_list: false, - description: Some( - "True enables max seeding time", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "max_seeding_time", - description: "Number of minutes to seed a torrent", - return_type: Number( - TypeInfo { - name: "max_seeding_time", - is_optional: false, - is_list: false, - description: Some( - "Number of minutes to seed a torrent", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "announce_ip", - description: "TODO", - return_type: String( - TypeInfo { - name: "announce_ip", - is_optional: false, - is_list: false, - description: Some( - "TODO", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "announce_to_all_tiers", - description: "True always announce to all tiers", - return_type: Bool( - TypeInfo { - name: "announce_to_all_tiers", - is_optional: false, - is_list: false, - description: Some( - "True always announce to all tiers", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "announce_to_all_trackers", - description: "True always announce to all trackers in a tier", - return_type: Bool( - TypeInfo { - name: "announce_to_all_trackers", - is_optional: false, - is_list: false, - description: Some( - "True always announce to all trackers in a tier", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "async_io_threads", - description: "Number of asynchronous I/O threads", - return_type: Number( - TypeInfo { - name: "async_io_threads", - is_optional: false, - is_list: false, - description: Some( - "Number of asynchronous I/O threads", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "banned_IPs", - description: "List of banned IPs", - return_type: String( - TypeInfo { - name: "banned_IPs", - is_optional: false, - is_list: false, - description: Some( - "List of banned IPs", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "checking_memory_use", - description: "Outstanding memory when checking torrents in MiB", - return_type: Number( - TypeInfo { - name: "checking_memory_use", - is_optional: false, - is_list: false, - description: Some( - "Outstanding memory when checking torrents in MiB", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "current_interface_address", - description: "IP Address to bind to. Empty String means All addresses", - return_type: String( - TypeInfo { - name: "current_interface_address", - is_optional: false, - is_list: false, - description: Some( - "IP Address to bind to. Empty String means All addresses", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "current_network_interface", - description: "Network Interface used", - return_type: String( - TypeInfo { - name: "current_network_interface", - is_optional: false, - is_list: false, - description: Some( - "Network Interface used", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "disk_cache", - description: "Disk cache used in MiB", - return_type: Number( - TypeInfo { - name: "disk_cache", - is_optional: false, - is_list: false, - description: Some( - "Disk cache used in MiB", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "disk_cache_ttl", - description: "Disk cache expiry interval in seconds", - return_type: Number( - TypeInfo { - name: "disk_cache_ttl", - is_optional: false, - is_list: false, - description: Some( - "Disk cache expiry interval in seconds", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "embedded_tracker_port", - description: "Port used for embedded tracker", - return_type: Number( - TypeInfo { - name: "embedded_tracker_port", - is_optional: false, - is_list: false, - description: Some( - "Port used for embedded tracker", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "enable_coalesce_read_write", - description: "True enables coalesce reads & writes", - return_type: Bool( - TypeInfo { - name: "enable_coalesce_read_write", - is_optional: false, - is_list: false, - description: Some( - "True enables coalesce reads & writes", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "enable_embedded_tracker", - description: "True enables embedded tracker", - return_type: Bool( - TypeInfo { - name: "enable_embedded_tracker", - is_optional: false, - is_list: false, - description: Some( - "True enables embedded tracker", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "enable_multi_connections_from_same_ip", - description: "True allows multiple connections from the same IP address", - return_type: Bool( - TypeInfo { - name: "enable_multi_connections_from_same_ip", - is_optional: false, - is_list: false, - description: Some( - "True allows multiple connections from the same IP address", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "enable_os_cache", - description: "True enables os cache", - return_type: Bool( - TypeInfo { - name: "enable_os_cache", - is_optional: false, - is_list: false, - description: Some( - "True enables os cache", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "enable_upload_suggestions", - description: "True enables sending of upload piece suggestions", - return_type: Bool( - TypeInfo { - name: "enable_upload_suggestions", - is_optional: false, - is_list: false, - description: Some( - "True enables sending of upload piece suggestions", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "file_pool_size", - description: "File pool size", - return_type: Number( - TypeInfo { - name: "file_pool_size", - is_optional: false, - is_list: false, - description: Some( - "File pool size", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "outgoing_ports_max", - description: "Maximal outgoing port (0: Disabled)", - return_type: Number( - TypeInfo { - name: "outgoing_ports_max", - is_optional: false, - is_list: false, - description: Some( - "Maximal outgoing port (0: Disabled)", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "outgoing_ports_min", - description: "Minimal outgoing port (0: Disabled)", - return_type: Number( - TypeInfo { - name: "outgoing_ports_min", - is_optional: false, - is_list: false, - description: Some( - "Minimal outgoing port (0: Disabled)", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "recheck_completed_torrents", - description: "True rechecks torrents on completion", - return_type: Bool( - TypeInfo { - name: "recheck_completed_torrents", - is_optional: false, - is_list: false, - description: Some( - "True rechecks torrents on completion", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "resolve_peer_countries", - description: "True resolves peer countries", - return_type: Bool( - TypeInfo { - name: "resolve_peer_countries", - is_optional: false, - is_list: false, - description: Some( - "True resolves peer countries", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "save_resume_data_interval", - description: "Save resume data interval in min", - return_type: Number( - TypeInfo { - name: "save_resume_data_interval", - is_optional: false, - is_list: false, - description: Some( - "Save resume data interval in min", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "send_buffer_low_watermark", - description: "Send buffer low watermark in KiB", - return_type: Number( - TypeInfo { - name: "send_buffer_low_watermark", - is_optional: false, - is_list: false, - description: Some( - "Send buffer low watermark in KiB", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "send_buffer_watermark", - description: "Send buffer watermark in KiB", - return_type: Number( - TypeInfo { - name: "send_buffer_watermark", - is_optional: false, - is_list: false, - description: Some( - "Send buffer watermark in KiB", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "send_buffer_watermark_factor", - description: "Send buffer watermark factor in percent", - return_type: Number( - TypeInfo { - name: "send_buffer_watermark_factor", - is_optional: false, - is_list: false, - description: Some( - "Send buffer watermark factor in percent", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "socket_backlog_size", - description: "Socket backlog size", - return_type: Number( - TypeInfo { - name: "socket_backlog_size", - is_optional: false, - is_list: false, - description: Some( - "Socket backlog size", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "upload_choking_algorithm", - description: "Upload choking algorithm used (see list of possible values below)", - return_type: Number( - TypeInfo { - name: "upload_choking_algorithm", - is_optional: false, - is_list: false, - description: Some( - "Upload choking algorithm used (see list of possible values below)", - ), - type_description: Some( - TypeDescription { - values: [ - TypeDescriptions { - value: "0", - description: "Round-robin", - }, - TypeDescriptions { - value: "1", - description: "Fastest upload", - }, - TypeDescriptions { - value: "2", - description: "Anti-leech", - }, - ], - }, - ), - }, - ), - }, - ReturnTypeParameter { - name: "upload_slots_behavior", - description: "Upload slots behavior used (see list of possible values below)", - return_type: Number( - TypeInfo { - name: "upload_slots_behavior", - is_optional: false, - is_list: false, - description: Some( - "Upload slots behavior used (see list of possible values below)", - ), - type_description: Some( - TypeDescription { - values: [ - TypeDescriptions { - value: "0", - description: "Fixed slots", - }, - TypeDescriptions { - value: "1", - description: "Upload rate based", - }, - ], - }, - ), - }, - ), - }, - ReturnTypeParameter { - name: "upnp_lease_duration", - description: "UPnP lease duration (0: Permanent lease)", - return_type: Number( - TypeInfo { - name: "upnp_lease_duration", - is_optional: false, - is_list: false, - description: Some( - "UPnP lease duration (0: Permanent lease)", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "utp_tcp_mixed_mode", - description: "μTP-TCP mixed mode algorithm (see list of possible values below)", - return_type: Number( - TypeInfo { - name: "utp_tcp_mixed_mode", - is_optional: false, - is_list: false, - description: Some( - "μTP-TCP mixed mode algorithm (see list of possible values below)", - ), - type_description: Some( - TypeDescription { - values: [ - TypeDescriptions { - value: "0", - description: "Prefer TCP", - }, - TypeDescriptions { - value: "1", - description: "Peer proportional", - }, - ], - }, - ), - }, - ), - }, - ], - }, - ), - url: "preferences", - }, - ApiMethod { - name: "setPreferences", - description: Some( - "1. There is no need to pass all possible preferences' `token:value` pairs if you only want to change one option\n 1. Paths in `scan_dirs` must exist, otherwise this option will have no effect\n 1. String values must be quoted; integer and boolean values must never be quoted\n\nFor a list of possible preference options see [Get application preferences](#get-application-preferences)", - ), - parameters: None, - return_type: None, - url: "setPreferences", - }, - ApiMethod { - name: "defaultSavePath", - description: None, - parameters: None, - return_type: None, - url: "defaultSavePath", - }, - ], - description: Some( - "All Application API methods are under \"app\", e.g.: `/api/v2/app/methodName`.", - ), - url: "app", - }, - ApiGroup { - name: "log", - methods: [ - ApiMethod { - name: "main", - description: Some( - "Each element of the array has the following properties:\n\nExample:\n\n```JSON\n[\n {\n \"id\":0,\n \"message\":\"qBittorrent v3.4.0 started\",\n \"timestamp\":1507969127860,\n \"type\":1\n },\n {\n \"id\":1,\n \"message\":\"qBittorrent is trying to listen on any interface port: 19036\",\n \"timestamp\":1507969127869,\n \"type\":2\n },\n {\n \"id\":2,\n \"message\":\"Peer ID: -qB3400-\",\n \"timestamp\":1507969127870,\n \"type\":1\n },\n {\n \"id\":3,\n \"message\":\"HTTP User-Agent is 'qBittorrent/3.4.0'\",\n \"timestamp\":1507969127870,\n \"type\":1\n },\n {\n \"id\":4,\n \"message\":\"DHT support [ON]\",\n \"timestamp\":1507969127871,\n \"type\":2\n },\n {\n \"id\":5,\n \"message\":\"Local Peer Discovery support [ON]\",\n \"timestamp\":1507969127871,\n \"type\":2\n },\n {\n \"id\":6,\n \"message\":\"PeX support [ON]\",\n \"timestamp\":1507969127871,\n \"type\":2\n },\n {\n \"id\":7,\n \"message\":\"Anonymous mode [OFF]\",\n \"timestamp\":1507969127871,\n \"type\":2\n },\n {\n \"id\":8,\n \"message\":\"Encryption support [ON]\",\n \"timestamp\":1507969127871,\n \"type\":2\n },\n {\n \"id\":9,\n \"message\":\"Embedded Tracker [OFF]\",\n \"timestamp\":1507969127871,\n \"type\":2\n },\n {\n \"id\":10,\n \"message\":\"UPnP / NAT-PMP support [ON]\",\n \"timestamp\":1507969127873,\n \"type\":2\n },\n {\n \"id\":11,\n \"message\":\"Web UI: Now listening on port 8080\",\n \"timestamp\":1507969127883,\n \"type\":1\n },\n {\n \"id\":12,\n \"message\":\"Options were saved successfully.\",\n \"timestamp\":1507969128055,\n \"type\":1\n },\n {\n \"id\":13,\n \"message\":\"qBittorrent is successfully listening on interface :: port: TCP/19036\",\n \"timestamp\":1507969128270,\n \"type\":2\n },\n {\n \"id\":14,\n \"message\":\"qBittorrent is successfully listening on interface 0.0.0.0 port: TCP/19036\",\n \"timestamp\":1507969128271,\n \"type\":2\n },\n {\n \"id\":15,\n \"message\":\"qBittorrent is successfully listening on interface 0.0.0.0 port: UDP/19036\",\n \"timestamp\":1507969128272,\n \"type\":2\n }\n]\n```", - ), - parameters: Some( - [ - Bool( - TypeInfo { - name: "normal", - is_optional: true, - is_list: false, - description: Some( - "Include normal messages (default: true)", - ), - type_description: None, - }, - ), - Bool( - TypeInfo { - name: "info", - is_optional: true, - is_list: false, - description: Some( - "Include info messages (default: true)", - ), - type_description: None, - }, - ), - Bool( - TypeInfo { - name: "warning", - is_optional: true, - is_list: false, - description: Some( - "Include warning messages (default: true)", - ), - type_description: None, - }, - ), - Bool( - TypeInfo { - name: "critical", - is_optional: true, - is_list: false, - description: Some( - "Include critical messages (default: true)", - ), - type_description: None, - }, - ), - Number( - TypeInfo { - name: "last_known_id", - is_optional: true, - is_list: false, - description: Some( - "Exclude messages with \"message id\" <= last_known_id (default: -1)", - ), - type_description: None, - }, - ), - ], - ), - return_type: Some( - ReturnType { - is_list: true, - parameters: [ - ReturnTypeParameter { - name: "id", - description: "ID of the message", - return_type: Number( - TypeInfo { - name: "id", - is_optional: false, - is_list: false, - description: Some( - "ID of the message", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "message", - description: "Text of the message", - return_type: String( - TypeInfo { - name: "message", - is_optional: false, - is_list: false, - description: Some( - "Text of the message", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "timestamp", - description: "Milliseconds since epoch", - return_type: Number( - TypeInfo { - name: "timestamp", - is_optional: false, - is_list: false, - description: Some( - "Milliseconds since epoch", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "type", - description: "Type of the message: Log::NORMAL: 1, Log::INFO: 2, Log::WARNING: 4, Log::CRITICAL: 8", - return_type: Number( - TypeInfo { - name: "type", - is_optional: false, - is_list: false, - description: Some( - "Type of the message: Log::NORMAL: 1, Log::INFO: 2, Log::WARNING: 4, Log::CRITICAL: 8", - ), - type_description: None, - }, - ), - }, - ], - }, - ), - url: "main", - }, - ApiMethod { - name: "peers", - description: None, - parameters: Some( - [ - Number( - TypeInfo { - name: "last_known_id", - is_optional: true, - is_list: false, - description: Some( - "Exclude messages with \"message id\" <= last_known_id (default: -1)", - ), - type_description: None, - }, - ), - ], - ), - return_type: None, - url: "peers", - }, - ], - description: Some( - "All Log API methods are under \"log\", e.g.: `/api/v2/log/methodName`.", - ), - url: "log", - }, - ApiGroup { - name: "sync", - methods: [ - ApiMethod { - name: "maindata", - description: Some( - "Example:\n\n```JSON\n{\n \"rid\":15,\n \"torrents\":\n {\n \"8c212779b4abde7c6bc608063a0d008b7e40ce32\":\n {\n \"state\":\"pausedUP\"\n }\n }\n}\n```", - ), - parameters: Some( - [ - Number( - TypeInfo { - name: "rid", - is_optional: false, - is_list: false, - description: Some( - "Response ID. If not provided, rid=0 will be assumed. If the given rid is different from the one of last server reply, full_update will be true (see the server reply details for more info)", - ), - type_description: None, - }, - ), - ], - ), - return_type: Some( - ReturnType { - is_list: false, - parameters: [ - ReturnTypeParameter { - name: "rid", - description: "Response ID", - return_type: Number( - TypeInfo { - name: "rid", - is_optional: false, - is_list: false, - description: Some( - "Response ID", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "full_update", - description: "Whether the response contains all the data or partial data", - return_type: Bool( - TypeInfo { - name: "full_update", - is_optional: false, - is_list: false, - description: Some( - "Whether the response contains all the data or partial data", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "torrents", - description: "Property: torrent hash, value: same as [torrent list](#get-torrent-list)", - return_type: Object( - TypeInfo { - name: "torrents", - is_optional: false, - is_list: false, - description: Some( - "Property: torrent hash, value: same as [torrent list](#get-torrent-list)", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "torrents_removed", - description: "List of hashes of torrents removed since last request", - return_type: StringArray( - TypeInfo { - name: "torrents_removed", - is_optional: false, - is_list: false, - description: Some( - "List of hashes of torrents removed since last request", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "categories", - description: "Info for categories added since last request", - return_type: Object( - TypeInfo { - name: "categories", - is_optional: false, - is_list: false, - description: Some( - "Info for categories added since last request", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "categories_removed", - description: "List of categories removed since last request", - return_type: StringArray( - TypeInfo { - name: "categories_removed", - is_optional: false, - is_list: false, - description: Some( - "List of categories removed since last request", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "tags", - description: "List of tags added since last request", - return_type: StringArray( - TypeInfo { - name: "tags", - is_optional: false, - is_list: false, - description: Some( - "List of tags added since last request", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "tags_removed", - description: "List of tags removed since last request", - return_type: StringArray( - TypeInfo { - name: "tags_removed", - is_optional: false, - is_list: false, - description: Some( - "List of tags removed since last request", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "server_state", - description: "Global transfer info", - return_type: Object( - TypeInfo { - name: "server_state", - is_optional: false, - is_list: false, - description: Some( - "Global transfer info", - ), - type_description: None, - }, - ), - }, - ], - }, - ), - url: "maindata", - }, - ApiMethod { - name: "torrentPeers", - description: None, - parameters: Some( - [ - String( - TypeInfo { - name: "hash", - is_optional: false, - is_list: false, - description: Some( - "Torrent hash", - ), - type_description: None, - }, - ), - Number( - TypeInfo { - name: "rid", - is_optional: false, - is_list: false, - description: Some( - "Response ID. If not provided, rid=0 will be assumed. If the given rid is different from the one of last server reply, full_update will be true (see the server reply details for more info)", - ), - type_description: None, - }, - ), - ], - ), - return_type: None, - url: "torrentPeers", - }, - ], - description: Some( - "Sync API implements requests for obtaining changes since the last request.\nAll Sync API methods are under \"sync\", e.g.: `/api/v2/sync/methodName`.", - ), - url: "sync", - }, - ApiGroup { - name: "transfer_info", - methods: [ - ApiMethod { - name: "info", - description: Some( - "In addition to the above in partial data requests (see [Get partial data](#get-partial-data) for more info):\n\nPossible values of `connection_status`:\n\nExample:\n\n```JSON\n{\n \"connection_status\":\"connected\",\n \"dht_nodes\":386,\n \"dl_info_data\":681521119,\n \"dl_info_speed\":0,\n \"dl_rate_limit\":0,\n \"up_info_data\":10747904,\n \"up_info_speed\":0,\n \"up_rate_limit\":1048576\n}\n```", - ), - parameters: None, - return_type: Some( - ReturnType { - is_list: false, - parameters: [ - ReturnTypeParameter { - name: "dl_info_speed", - description: "Global download rate (bytes/s)", - return_type: Number( - TypeInfo { - name: "dl_info_speed", - is_optional: false, - is_list: false, - description: Some( - "Global download rate (bytes/s)", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "dl_info_data", - description: "Data downloaded this session (bytes)", - return_type: Number( - TypeInfo { - name: "dl_info_data", - is_optional: false, - is_list: false, - description: Some( - "Data downloaded this session (bytes)", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "up_info_speed", - description: "Global upload rate (bytes/s)", - return_type: Number( - TypeInfo { - name: "up_info_speed", - is_optional: false, - is_list: false, - description: Some( - "Global upload rate (bytes/s)", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "up_info_data", - description: "Data uploaded this session (bytes)", - return_type: Number( - TypeInfo { - name: "up_info_data", - is_optional: false, - is_list: false, - description: Some( - "Data uploaded this session (bytes)", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "dl_rate_limit", - description: "Download rate limit (bytes/s)", - return_type: Number( - TypeInfo { - name: "dl_rate_limit", - is_optional: false, - is_list: false, - description: Some( - "Download rate limit (bytes/s)", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "up_rate_limit", - description: "Upload rate limit (bytes/s)", - return_type: Number( - TypeInfo { - name: "up_rate_limit", - is_optional: false, - is_list: false, - description: Some( - "Upload rate limit (bytes/s)", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "dht_nodes", - description: "DHT nodes connected to", - return_type: Number( - TypeInfo { - name: "dht_nodes", - is_optional: false, - is_list: false, - description: Some( - "DHT nodes connected to", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "connection_status", - description: "Connection status. See possible values here below", - return_type: String( - TypeInfo { - name: "connection_status", - is_optional: false, - is_list: false, - description: Some( - "Connection status. See possible values here below", - ), - type_description: Some( - TypeDescription { - values: [ - TypeDescriptions { - value: "connected", - description: "", - }, - TypeDescriptions { - value: "firewalled", - description: "", - }, - TypeDescriptions { - value: "disconnected", - description: "", - }, - ], - }, - ), - }, - ), - }, - ], - }, - ), - url: "info", - }, - ApiMethod { - name: "speedLimitsMode", - description: None, - parameters: None, - return_type: None, - url: "speedLimitsMode", - }, - ApiMethod { - name: "toggleSpeedLimitsMode", - description: None, - parameters: None, - return_type: None, - url: "toggleSpeedLimitsMode", - }, - ApiMethod { - name: "downloadLimit", - description: None, - parameters: None, - return_type: None, - url: "downloadLimit", - }, - ApiMethod { - name: "setDownloadLimit", - description: None, - parameters: Some( - [ - Number( - TypeInfo { - name: "limit", - is_optional: false, - is_list: false, - description: Some( - "The global download speed limit to set in bytes/second", - ), - type_description: None, - }, - ), - ], - ), - return_type: None, - url: "setDownloadLimit", - }, - ApiMethod { - name: "uploadLimit", - description: None, - parameters: None, - return_type: None, - url: "uploadLimit", - }, - ApiMethod { - name: "setUploadLimit", - description: None, - parameters: Some( - [ - Number( - TypeInfo { - name: "limit", - is_optional: false, - is_list: false, - description: Some( - "The global upload speed limit to set in bytes/second", - ), - type_description: None, - }, - ), - ], - ), - return_type: None, - url: "setUploadLimit", - }, - ApiMethod { - name: "banPeers", - description: None, - parameters: Some( - [ - String( - TypeInfo { - name: "peers", - is_optional: false, - is_list: false, - description: Some( - "The peer to ban, or multiple peers separated by a pipe \\", - ), - type_description: None, - }, - ), - ], - ), - return_type: None, - url: "banPeers", - }, - ], - description: Some( - "All Transfer info API methods are under \"transfer\", e.g.: `/api/v2/transfer/methodName`.", - ), - url: "transfer", - }, - ApiGroup { - name: "torrent_management", - methods: [ - ApiMethod { - name: "info", - description: Some( - "Possible values of `state`:\n\nExample:\n\n```JSON\n[\n {\n \"dlspeed\":9681262,\n \"eta\":87,\n \"f_l_piece_prio\":false,\n \"force_start\":false,\n \"hash\":\"8c212779b4abde7c6bc608063a0d008b7e40ce32\",\n \"category\":\"\",\n \"tags\": \"\",\n \"name\":\"debian-8.1.0-amd64-CD-1.iso\",\n \"num_complete\":-1,\n \"num_incomplete\":-1,\n \"num_leechs\":2,\n \"num_seeds\":54,\n \"priority\":1,\n \"progress\":0.16108787059783936,\n \"ratio\":0,\n \"seq_dl\":false,\n \"size\":657457152,\n \"state\":\"downloading\",\n \"super_seeding\":false,\n \"upspeed\":0\n },\n {\n another_torrent_info\n }\n]\n```", - ), - parameters: Some( - [ - String( - TypeInfo { - name: "filter", - is_optional: true, - is_list: false, - description: Some( - "Filter torrent list by state. Allowed state filters: all, downloading, seeding, completed, paused, active, inactive, resumed, stalled, stalled_uploading, stalled_downloading, errored", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "category", - is_optional: true, - is_list: false, - description: Some( - "Get torrents with the given category (empty string means \"without category\"; no \"category\" parameter means \"any category\" <- broken until [#11748](https://github.com/qbittorrent/qBittorrent/issues/11748) is resolved). Remember to URL-encode the category name. For example, My category becomes My%20category", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "tag", - is_optional: true, - is_list: false, - description: Some( - "Get torrents with the given tag (empty string means \"without tag\"; no \"tag\" parameter means \"any tag\". Remember to URL-encode the category name. For example, My tag becomes My%20tag", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "sort", - is_optional: true, - is_list: false, - description: Some( - "Sort torrents by given key. They can be sorted using any field of the response's JSON array (which are documented below) as the sort key.", - ), - type_description: None, - }, - ), - Bool( - TypeInfo { - name: "reverse", - is_optional: true, - is_list: false, - description: Some( - "Enable reverse sorting. Defaults to false", - ), - type_description: None, - }, - ), - Number( - TypeInfo { - name: "limit", - is_optional: true, - is_list: false, - description: Some( - "Limit the number of torrents returned", - ), - type_description: None, - }, - ), - Number( - TypeInfo { - name: "offset", - is_optional: true, - is_list: false, - description: Some( - "Set offset (if less than 0, offset from end)", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "hashes", - is_optional: true, - is_list: false, - description: Some( - "Filter by hashes. Can contain multiple hashes separated by \\", - ), - type_description: None, - }, - ), - ], - ), - return_type: Some( - ReturnType { - is_list: true, - parameters: [ - ReturnTypeParameter { - name: "added_on", - description: "Time (Unix Epoch) when the torrent was added to the client", - return_type: Number( - TypeInfo { - name: "added_on", - is_optional: false, - is_list: false, - description: Some( - "Time (Unix Epoch) when the torrent was added to the client", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "amount_left", - description: "Amount of data left to download (bytes)", - return_type: Number( - TypeInfo { - name: "amount_left", - is_optional: false, - is_list: false, - description: Some( - "Amount of data left to download (bytes)", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "auto_tmm", - description: "Whether this torrent is managed by Automatic Torrent Management", - return_type: Bool( - TypeInfo { - name: "auto_tmm", - is_optional: false, - is_list: false, - description: Some( - "Whether this torrent is managed by Automatic Torrent Management", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "availability", - description: "Percentage of file pieces currently available", - return_type: Float( - TypeInfo { - name: "availability", - is_optional: false, - is_list: false, - description: Some( - "Percentage of file pieces currently available", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "category", - description: "Category of the torrent", - return_type: String( - TypeInfo { - name: "category", - is_optional: false, - is_list: false, - description: Some( - "Category of the torrent", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "completed", - description: "Amount of transfer data completed (bytes)", - return_type: Number( - TypeInfo { - name: "completed", - is_optional: false, - is_list: false, - description: Some( - "Amount of transfer data completed (bytes)", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "completion_on", - description: "Time (Unix Epoch) when the torrent completed", - return_type: Number( - TypeInfo { - name: "completion_on", - is_optional: false, - is_list: false, - description: Some( - "Time (Unix Epoch) when the torrent completed", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "content_path", - description: "Absolute path of torrent content (root path for multifile torrents, absolute file path for singlefile torrents)", - return_type: String( - TypeInfo { - name: "content_path", - is_optional: false, - is_list: false, - description: Some( - "Absolute path of torrent content (root path for multifile torrents, absolute file path for singlefile torrents)", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "dl_limit", - description: "Torrent download speed limit (bytes/s). -1 if ulimited.", - return_type: Number( - TypeInfo { - name: "dl_limit", - is_optional: false, - is_list: false, - description: Some( - "Torrent download speed limit (bytes/s). -1 if ulimited.", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "dlspeed", - description: "Torrent download speed (bytes/s)", - return_type: Number( - TypeInfo { - name: "dlspeed", - is_optional: false, - is_list: false, - description: Some( - "Torrent download speed (bytes/s)", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "downloaded", - description: "Amount of data downloaded", - return_type: Number( - TypeInfo { - name: "downloaded", - is_optional: false, - is_list: false, - description: Some( - "Amount of data downloaded", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "downloaded_session", - description: "Amount of data downloaded this session", - return_type: Number( - TypeInfo { - name: "downloaded_session", - is_optional: false, - is_list: false, - description: Some( - "Amount of data downloaded this session", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "eta", - description: "Torrent ETA (seconds)", - return_type: Number( - TypeInfo { - name: "eta", - is_optional: false, - is_list: false, - description: Some( - "Torrent ETA (seconds)", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "f_l_piece_prio", - description: "True if first last piece are prioritized", - return_type: Bool( - TypeInfo { - name: "f_l_piece_prio", - is_optional: false, - is_list: false, - description: Some( - "True if first last piece are prioritized", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "force_start", - description: "True if force start is enabled for this torrent", - return_type: Bool( - TypeInfo { - name: "force_start", - is_optional: false, - is_list: false, - description: Some( - "True if force start is enabled for this torrent", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "hash", - description: "Torrent hash", - return_type: String( - TypeInfo { - name: "hash", - is_optional: false, - is_list: false, - description: Some( - "Torrent hash", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "last_activity", - description: "Last time (Unix Epoch) when a chunk was downloaded/uploaded", - return_type: Number( - TypeInfo { - name: "last_activity", - is_optional: false, - is_list: false, - description: Some( - "Last time (Unix Epoch) when a chunk was downloaded/uploaded", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "magnet_uri", - description: "Magnet URI corresponding to this torrent", - return_type: String( - TypeInfo { - name: "magnet_uri", - is_optional: false, - is_list: false, - description: Some( - "Magnet URI corresponding to this torrent", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "max_ratio", - description: "Maximum share ratio until torrent is stopped from seeding/uploading", - return_type: Float( - TypeInfo { - name: "max_ratio", - is_optional: false, - is_list: false, - description: Some( - "Maximum share ratio until torrent is stopped from seeding/uploading", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "max_seeding_time", - description: "Maximum seeding time (seconds) until torrent is stopped from seeding", - return_type: Number( - TypeInfo { - name: "max_seeding_time", - is_optional: false, - is_list: false, - description: Some( - "Maximum seeding time (seconds) until torrent is stopped from seeding", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "name", - description: "Torrent name", - return_type: String( - TypeInfo { - name: "name", - is_optional: false, - is_list: false, - description: Some( - "Torrent name", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "num_complete", - description: "Number of seeds in the swarm", - return_type: Number( - TypeInfo { - name: "num_complete", - is_optional: false, - is_list: false, - description: Some( - "Number of seeds in the swarm", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "num_incomplete", - description: "Number of leechers in the swarm", - return_type: Number( - TypeInfo { - name: "num_incomplete", - is_optional: false, - is_list: false, - description: Some( - "Number of leechers in the swarm", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "num_leechs", - description: "Number of leechers connected to", - return_type: Number( - TypeInfo { - name: "num_leechs", - is_optional: false, - is_list: false, - description: Some( - "Number of leechers connected to", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "num_seeds", - description: "Number of seeds connected to", - return_type: Number( - TypeInfo { - name: "num_seeds", - is_optional: false, - is_list: false, - description: Some( - "Number of seeds connected to", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "priority", - description: "Torrent priority. Returns -1 if queuing is disabled or torrent is in seed mode", - return_type: Number( - TypeInfo { - name: "priority", - is_optional: false, - is_list: false, - description: Some( - "Torrent priority. Returns -1 if queuing is disabled or torrent is in seed mode", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "progress", - description: "Torrent progress (percentage/100)", - return_type: Float( - TypeInfo { - name: "progress", - is_optional: false, - is_list: false, - description: Some( - "Torrent progress (percentage/100)", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "ratio", - description: "Torrent share ratio. Max ratio value: 9999.", - return_type: Float( - TypeInfo { - name: "ratio", - is_optional: false, - is_list: false, - description: Some( - "Torrent share ratio. Max ratio value: 9999.", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "ratio_limit", - description: "TODO (what is different from max_ratio?)", - return_type: Float( - TypeInfo { - name: "ratio_limit", - is_optional: false, - is_list: false, - description: Some( - "TODO (what is different from max_ratio?)", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "save_path", - description: "Path where this torrent's data is stored", - return_type: String( - TypeInfo { - name: "save_path", - is_optional: false, - is_list: false, - description: Some( - "Path where this torrent's data is stored", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "seeding_time", - description: "Torrent elapsed time while complete (seconds)", - return_type: Number( - TypeInfo { - name: "seeding_time", - is_optional: false, - is_list: false, - description: Some( - "Torrent elapsed time while complete (seconds)", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "seeding_time_limit", - description: "TODO (what is different from max_seeding_time?) seeding_time_limit is a per torrent setting, when Automatic Torrent Management is disabled, furthermore then max_seeding_time is set to seeding_time_limit for this torrent. If Automatic Torrent Management is enabled, the value is -2. And if max_seeding_time is unset it have a default value -1.", - return_type: Number( - TypeInfo { - name: "seeding_time_limit", - is_optional: false, - is_list: false, - description: Some( - "TODO (what is different from max_seeding_time?) seeding_time_limit is a per torrent setting, when Automatic Torrent Management is disabled, furthermore then max_seeding_time is set to seeding_time_limit for this torrent. If Automatic Torrent Management is enabled, the value is -2. And if max_seeding_time is unset it have a default value -1.", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "seen_complete", - description: "Time (Unix Epoch) when this torrent was last seen complete", - return_type: Number( - TypeInfo { - name: "seen_complete", - is_optional: false, - is_list: false, - description: Some( - "Time (Unix Epoch) when this torrent was last seen complete", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "seq_dl", - description: "True if sequential download is enabled", - return_type: Bool( - TypeInfo { - name: "seq_dl", - is_optional: false, - is_list: false, - description: Some( - "True if sequential download is enabled", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "size", - description: "Total size (bytes) of files selected for download", - return_type: Number( - TypeInfo { - name: "size", - is_optional: false, - is_list: false, - description: Some( - "Total size (bytes) of files selected for download", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "state", - description: "Torrent state. See table here below for the possible values", - return_type: String( - TypeInfo { - name: "state", - is_optional: false, - is_list: false, - description: Some( - "Torrent state. See table here below for the possible values", - ), - type_description: Some( - TypeDescription { - values: [ - TypeDescriptions { - value: "error", - description: "Some error occurred, applies to paused torrents", - }, - TypeDescriptions { - value: "missingFiles", - description: "Torrent data files is missing", - }, - TypeDescriptions { - value: "uploading", - description: "Torrent is being seeded and data is being transferred", - }, - TypeDescriptions { - value: "pausedUP", - description: "Torrent is paused and has finished downloading", - }, - TypeDescriptions { - value: "queuedUP", - description: "Queuing is enabled and torrent is queued for upload", - }, - TypeDescriptions { - value: "stalledUP", - description: "Torrent is being seeded, but no connection were made", - }, - TypeDescriptions { - value: "checkingUP", - description: "Torrent has finished downloading and is being checked", - }, - TypeDescriptions { - value: "forcedUP", - description: "Torrent is forced to uploading and ignore queue limit", - }, - TypeDescriptions { - value: "allocating", - description: "Torrent is allocating disk space for download", - }, - TypeDescriptions { - value: "downloading", - description: "Torrent is being downloaded and data is being transferred", - }, - TypeDescriptions { - value: "metaDL", - description: "Torrent has just started downloading and is fetching metadata", - }, - TypeDescriptions { - value: "pausedDL", - description: "Torrent is paused and has NOT finished downloading", - }, - TypeDescriptions { - value: "queuedDL", - description: "Queuing is enabled and torrent is queued for download", - }, - TypeDescriptions { - value: "stalledDL", - description: "Torrent is being downloaded, but no connection were made", - }, - TypeDescriptions { - value: "checkingDL", - description: "Same as checkingUP, but torrent has NOT finished downloading", - }, - TypeDescriptions { - value: "forcedDL", - description: "Torrent is forced to downloading to ignore queue limit", - }, - TypeDescriptions { - value: "checkingResumeData", - description: "Checking resume data on qBt startup", - }, - TypeDescriptions { - value: "moving", - description: "Torrent is moving to another location", - }, - TypeDescriptions { - value: "unknown", - description: "Unknown status", - }, - ], - }, - ), - }, - ), - }, - ReturnTypeParameter { - name: "super_seeding", - description: "True if super seeding is enabled", - return_type: Bool( - TypeInfo { - name: "super_seeding", - is_optional: false, - is_list: false, - description: Some( - "True if super seeding is enabled", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "tags", - description: "Comma-concatenated tag list of the torrent", - return_type: String( - TypeInfo { - name: "tags", - is_optional: false, - is_list: false, - description: Some( - "Comma-concatenated tag list of the torrent", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "time_active", - description: "Total active time (seconds)", - return_type: Number( - TypeInfo { - name: "time_active", - is_optional: false, - is_list: false, - description: Some( - "Total active time (seconds)", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "total_size", - description: "Total size (bytes) of all file in this torrent (including unselected ones)", - return_type: Number( - TypeInfo { - name: "total_size", - is_optional: false, - is_list: false, - description: Some( - "Total size (bytes) of all file in this torrent (including unselected ones)", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "tracker", - description: "The first tracker with working status. Returns empty string if no tracker is working.", - return_type: String( - TypeInfo { - name: "tracker", - is_optional: false, - is_list: false, - description: Some( - "The first tracker with working status. Returns empty string if no tracker is working.", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "up_limit", - description: "Torrent upload speed limit (bytes/s). -1 if ulimited.", - return_type: Number( - TypeInfo { - name: "up_limit", - is_optional: false, - is_list: false, - description: Some( - "Torrent upload speed limit (bytes/s). -1 if ulimited.", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "uploaded", - description: "Amount of data uploaded", - return_type: Number( - TypeInfo { - name: "uploaded", - is_optional: false, - is_list: false, - description: Some( - "Amount of data uploaded", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "uploaded_session", - description: "Amount of data uploaded this session", - return_type: Number( - TypeInfo { - name: "uploaded_session", - is_optional: false, - is_list: false, - description: Some( - "Amount of data uploaded this session", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "upspeed", - description: "Torrent upload speed (bytes/s)", - return_type: Number( - TypeInfo { - name: "upspeed", - is_optional: false, - is_list: false, - description: Some( - "Torrent upload speed (bytes/s)", - ), - type_description: None, - }, - ), - }, - ], - }, - ), - url: "info", - }, - ApiMethod { - name: "properties", - description: Some( - "- empty, if the torrent hash is invalid\n- otherwise, a JSON object with the following fields\n\nNB: `-1` is returned if the type of the property is integer but its value is not known.\n\nExample:\n\n```JSON\n{\n \"addition_date\":1438429165,\n \"comment\":\"\\\"Debian CD from cdimage.debian.org\\\"\",\n \"completion_date\":1438429234,\n \"created_by\":\"\",\n \"creation_date\":1433605214,\n \"dl_limit\":-1,\n \"dl_speed\":0,\n \"dl_speed_avg\":9736015,\n \"eta\":8640000,\n \"last_seen\":1438430354,\n \"nb_connections\":3,\n \"nb_connections_limit\":250,\n \"peers\":1,\n \"peers_total\":89,\n \"piece_size\":524288,\n \"pieces_have\":1254,\n \"pieces_num\":1254,\n \"reannounce\":672,\n \"save_path\":\"/Downloads/debian-8.1.0-amd64-CD-1.iso\",\n \"seeding_time\":1128,\n \"seeds\":1,\n \"seeds_total\":254,\n \"share_ratio\":0.00072121022562178299,\n \"time_elapsed\":1197,\n \"total_downloaded\":681521119,\n \"total_downloaded_session\":681521119,\n \"total_size\":657457152,\n \"total_uploaded\":491520,\n \"total_uploaded_session\":491520,\n \"total_wasted\":23481724,\n \"up_limit\":-1,\n \"up_speed\":0,\n \"up_speed_avg\":410\n}\n```", - ), - parameters: Some( - [ - String( - TypeInfo { - name: "hash", - is_optional: false, - is_list: false, - description: Some( - "The hash of the torrent you want to get the generic properties of", - ), - type_description: None, - }, - ), - ], - ), - return_type: None, - url: "properties", - }, - ApiMethod { - name: "trackers", - description: Some( - "Possible values of `status`:\n\nExample:\n\n```JSON\n[\n {\n \"msg\":\"\",\n \"num_peers\":100,\n \"status\":2,\n \"url\":\"http://bttracker.debian.org:6969/announce\"\n },\n {\n another_tracker_info\n }\n]\n```", - ), - parameters: Some( - [ - String( - TypeInfo { - name: "hash", - is_optional: false, - is_list: false, - description: Some( - "The hash of the torrent you want to get the trackers of", - ), - type_description: None, - }, - ), - ], - ), - return_type: Some( - ReturnType { - is_list: true, - parameters: [ - ReturnTypeParameter { - name: "url", - description: "Tracker url", - return_type: String( - TypeInfo { - name: "url", - is_optional: false, - is_list: false, - description: Some( - "Tracker url", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "status", - description: "Tracker status. See the table below for possible values", - return_type: Number( - TypeInfo { - name: "status", - is_optional: false, - is_list: false, - description: Some( - "Tracker status. See the table below for possible values", - ), - type_description: Some( - TypeDescription { - values: [ - TypeDescriptions { - value: "0", - description: "Tracker is disabled (used for DHT, PeX, and LSD)", - }, - TypeDescriptions { - value: "1", - description: "Tracker has not been contacted yet", - }, - TypeDescriptions { - value: "2", - description: "Tracker has been contacted and is working", - }, - TypeDescriptions { - value: "3", - description: "Tracker is updating", - }, - TypeDescriptions { - value: "4", - description: "Tracker has been contacted, but it is not working (or doesn't send proper replies)", - }, - ], - }, - ), - }, - ), - }, - ReturnTypeParameter { - name: "tier", - description: "Tracker priority tier. Lower tier trackers are tried before higher tiers. Tier numbers are valid when >= 0, < 0 is used as placeholder when tier does not exist for special entries (such as DHT).", - return_type: Number( - TypeInfo { - name: "tier", - is_optional: false, - is_list: false, - description: Some( - "Tracker priority tier. Lower tier trackers are tried before higher tiers. Tier numbers are valid when >= 0, < 0 is used as placeholder when tier does not exist for special entries (such as DHT).", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "num_peers", - description: "Number of peers for current torrent, as reported by the tracker", - return_type: Number( - TypeInfo { - name: "num_peers", - is_optional: false, - is_list: false, - description: Some( - "Number of peers for current torrent, as reported by the tracker", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "num_seeds", - description: "Number of seeds for current torrent, asreported by the tracker", - return_type: Number( - TypeInfo { - name: "num_seeds", - is_optional: false, - is_list: false, - description: Some( - "Number of seeds for current torrent, asreported by the tracker", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "num_leeches", - description: "Number of leeches for current torrent, as reported by the tracker", - return_type: Number( - TypeInfo { - name: "num_leeches", - is_optional: false, - is_list: false, - description: Some( - "Number of leeches for current torrent, as reported by the tracker", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "num_downloaded", - description: "Number of completed downlods for current torrent, as reported by the tracker", - return_type: Number( - TypeInfo { - name: "num_downloaded", - is_optional: false, - is_list: false, - description: Some( - "Number of completed downlods for current torrent, as reported by the tracker", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "msg", - description: "Tracker message (there is no way of knowing what this message is - it's up to tracker admins)", - return_type: String( - TypeInfo { - name: "msg", - is_optional: false, - is_list: false, - description: Some( - "Tracker message (there is no way of knowing what this message is - it's up to tracker admins)", - ), - type_description: None, - }, - ), - }, - ], - }, - ), - url: "trackers", - }, - ApiMethod { - name: "webseeds", - description: Some( - "Example:\n\n```JSON\n[\n {\n \"url\":\"http://some_url/\"\n },\n {\n \"url\":\"http://some_other_url/\"\n }\n]\n```", - ), - parameters: Some( - [ - String( - TypeInfo { - name: "hash", - is_optional: false, - is_list: false, - description: Some( - "The hash of the torrent you want to get the webseeds of", - ), - type_description: None, - }, - ), - ], - ), - return_type: Some( - ReturnType { - is_list: true, - parameters: [ - ReturnTypeParameter { - name: "url", - description: "URL of the web seed", - return_type: String( - TypeInfo { - name: "url", - is_optional: false, - is_list: false, - description: Some( - "URL of the web seed", - ), - type_description: None, - }, - ), - }, - ], - }, - ), - url: "webseeds", - }, - ApiMethod { - name: "files", - description: Some( - "- empty, if the torrent hash is invalid\n- otherwise, a JSON array, where each element contains info about one file, with the following fields\n\nPossible values of `priority`:\n\nExample:\n\n```JSON\n\n[\n {\n \"index\":0,\n \"is_seed\":false,\n \"name\":\"debian-8.1.0-amd64-CD-1.iso\",\n \"piece_range\":[0,1253],\n \"priority\":1,\n \"progress\":0,\n \"size\":657457152,\n \"availability\":0.5,\n }\n]\n```", - ), - parameters: Some( - [ - String( - TypeInfo { - name: "hash", - is_optional: false, - is_list: false, - description: Some( - "The hash of the torrent you want to get the contents of", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "indexes", - is_optional: true, - is_list: false, - description: Some( - "The indexes of the files you want to retrieve. indexes can contain multiple values separated by \\", - ), - type_description: None, - }, - ), - ], - ), - return_type: None, - url: "files", - }, - ApiMethod { - name: "pieceStates", - description: Some( - "- empty, if the torrent hash is invalid\n- otherwise, an array of states (integers) of all pieces (in order) of a specific torrent.\n\nValue meanings are defined as below:\n\nExample:\n\n```JSON\n[0,0,2,1,0,0,2,1]\n```", - ), - parameters: Some( - [ - String( - TypeInfo { - name: "hash", - is_optional: false, - is_list: false, - description: Some( - "The hash of the torrent you want to get the pieces' states of", - ), - type_description: None, - }, - ), - ], - ), - return_type: None, - url: "pieceStates", - }, - ApiMethod { - name: "pieceHashes", - description: Some( - "- empty, if the torrent hash is invalid\n- otherwise, an array of hashes (strings) of all pieces (in order) of a specific torrent.\n\nExample:\n\n```JSON\n[\"54eddd830a5b58480a6143d616a97e3a6c23c439\",\"f8a99d225aa4241db100f88407fc3bdaead583ab\",\"928fb615b9bd4dd8f9e9022552c8f8f37ef76f58\"]\n```", - ), - parameters: Some( - [ - String( - TypeInfo { - name: "hash", - is_optional: false, - is_list: false, - description: Some( - "The hash of the torrent you want to get the pieces' hashes of", - ), - type_description: None, - }, - ), - ], - ), - return_type: None, - url: "pieceHashes", - }, - ApiMethod { - name: "pause", - description: None, - parameters: Some( - [ - String( - TypeInfo { - name: "hashes", - is_optional: false, - is_list: false, - description: Some( - "The hashes of the torrents you want to pause. hashes can contain multiple hashes separated by \\", - ), - type_description: None, - }, - ), - ], - ), - return_type: None, - url: "pause", - }, - ApiMethod { - name: "resume", - description: None, - parameters: Some( - [ - String( - TypeInfo { - name: "hashes", - is_optional: false, - is_list: false, - description: Some( - "The hashes of the torrents you want to resume. hashes can contain multiple hashes separated by \\", - ), - type_description: None, - }, - ), - ], - ), - return_type: None, - url: "resume", - }, - ApiMethod { - name: "delete", - description: None, - parameters: Some( - [ - String( - TypeInfo { - name: "hashes", - is_optional: false, - is_list: false, - description: Some( - "The hashes of the torrents you want to delete. hashes can contain multiple hashes separated by \\", - ), - type_description: None, - }, - ), - ], - ), - return_type: None, - url: "delete", - }, - ApiMethod { - name: "recheck", - description: None, - parameters: Some( - [ - String( - TypeInfo { - name: "hashes", - is_optional: false, - is_list: false, - description: Some( - "The hashes of the torrents you want to recheck. hashes can contain multiple hashes separated by \\", - ), - type_description: None, - }, - ), - ], - ), - return_type: None, - url: "recheck", - }, - ApiMethod { - name: "reannounce", - description: None, - parameters: Some( - [ - String( - TypeInfo { - name: "hashes", - is_optional: false, - is_list: false, - description: Some( - "The hashes of the torrents you want to reannounce. hashes can contain multiple hashes separated by \\", - ), - type_description: None, - }, - ), - ], - ), - return_type: None, - url: "reannounce", - }, - ApiMethod { - name: "add", - description: None, - parameters: Some( - [ - String( - TypeInfo { - name: "urls", - is_optional: false, - is_list: false, - description: Some( - "URLs separated with newlines", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "savepath", - is_optional: true, - is_list: false, - description: Some( - "Download folder", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "cookie", - is_optional: true, - is_list: false, - description: Some( - "Cookie sent to download the .torrent file", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "category", - is_optional: true, - is_list: false, - description: Some( - "Category for the torrent", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "tags", - is_optional: true, - is_list: false, - description: Some( - "Tags for the torrent, split by ','", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "skip_checking", - is_optional: true, - is_list: false, - description: Some( - "Skip hash checking. Possible values are true, false (default)", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "paused", - is_optional: true, - is_list: false, - description: Some( - "Add torrents in the paused state. Possible values are true, false (default)", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "root_folder", - is_optional: true, - is_list: false, - description: Some( - "Create the root folder. Possible values are true, false, unset (default)", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "rename", - is_optional: true, - is_list: false, - description: Some( - "Rename torrent", - ), - type_description: None, - }, - ), - Number( - TypeInfo { - name: "upLimit", - is_optional: true, - is_list: false, - description: Some( - "Set torrent upload speed limit. Unit in bytes/second", - ), - type_description: None, - }, - ), - Number( - TypeInfo { - name: "dlLimit", - is_optional: true, - is_list: false, - description: Some( - "Set torrent download speed limit. Unit in bytes/second", - ), - type_description: None, - }, - ), - Float( - TypeInfo { - name: "ratioLimit", - is_optional: true, - is_list: false, - description: Some( - "Set torrent share ratio limit", - ), - type_description: None, - }, - ), - Number( - TypeInfo { - name: "seedingTimeLimit", - is_optional: true, - is_list: false, - description: Some( - "Set torrent seeding time limit. Unit in seconds", - ), - type_description: None, - }, - ), - Bool( - TypeInfo { - name: "autoTMM", - is_optional: true, - is_list: false, - description: Some( - "Whether Automatic Torrent Management should be used", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "sequentialDownload", - is_optional: true, - is_list: false, - description: Some( - "Enable sequential download. Possible values are true, false (default)", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "firstLastPiecePrio", - is_optional: true, - is_list: false, - description: Some( - "Prioritize download first last piece. Possible values are true, false (default)", - ), - type_description: None, - }, - ), - ], - ), - return_type: None, - url: "add", - }, - ApiMethod { - name: "addTrackers", - description: None, - parameters: None, - return_type: None, - url: "addTrackers", - }, - ApiMethod { - name: "editTracker", - description: None, - parameters: Some( - [ - String( - TypeInfo { - name: "hash", - is_optional: false, - is_list: false, - description: Some( - "The hash of the torrent", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "origUrl", - is_optional: false, - is_list: false, - description: Some( - "The tracker URL you want to edit", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "newUrl", - is_optional: false, - is_list: false, - description: Some( - "The new URL to replace the origUrl", - ), - type_description: None, - }, - ), - ], - ), - return_type: None, - url: "editTracker", - }, - ApiMethod { - name: "removeTrackers", - description: None, - parameters: Some( - [ - String( - TypeInfo { - name: "hash", - is_optional: false, - is_list: false, - description: Some( - "The hash of the torrent", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "urls", - is_optional: false, - is_list: false, - description: Some( - "URLs to remove, separated by \\", - ), - type_description: None, - }, - ), - ], - ), - return_type: None, - url: "removeTrackers", - }, - ApiMethod { - name: "addPeers", - description: None, - parameters: Some( - [ - String( - TypeInfo { - name: "hashes", - is_optional: false, - is_list: false, - description: Some( - "The hash of the torrent, or multiple hashes separated by a pipe \\", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "peers", - is_optional: false, - is_list: false, - description: Some( - "The peer to add, or multiple peers separated by a pipe \\", - ), - type_description: None, - }, - ), - ], - ), - return_type: None, - url: "addPeers", - }, - ApiMethod { - name: "increasePrio", - description: None, - parameters: Some( - [ - String( - TypeInfo { - name: "hashes", - is_optional: false, - is_list: false, - description: Some( - "The hashes of the torrents you want to increase the priority of. hashes can contain multiple hashes separated by \\", - ), - type_description: None, - }, - ), - ], - ), - return_type: None, - url: "increasePrio", - }, - ApiMethod { - name: "decreasePrio", - description: None, - parameters: Some( - [ - String( - TypeInfo { - name: "hashes", - is_optional: false, - is_list: false, - description: Some( - "The hashes of the torrents you want to decrease the priority of. hashes can contain multiple hashes separated by \\", - ), - type_description: None, - }, - ), - ], - ), - return_type: None, - url: "decreasePrio", - }, - ApiMethod { - name: "topPrio", - description: None, - parameters: Some( - [ - String( - TypeInfo { - name: "hashes", - is_optional: false, - is_list: false, - description: Some( - "The hashes of the torrents you want to set to the maximum priority. hashes can contain multiple hashes separated by \\", - ), - type_description: None, - }, - ), - ], - ), - return_type: None, - url: "topPrio", - }, - ApiMethod { - name: "bottomPrio", - description: None, - parameters: Some( - [ - String( - TypeInfo { - name: "hashes", - is_optional: false, - is_list: false, - description: Some( - "The hashes of the torrents you want to set to the minimum priority. hashes can contain multiple hashes separated by \\", - ), - type_description: None, - }, - ), - ], - ), - return_type: None, - url: "bottomPrio", - }, - ApiMethod { - name: "filePrio", - description: None, - parameters: Some( - [ - String( - TypeInfo { - name: "hash", - is_optional: false, - is_list: false, - description: Some( - "The hash of the torrent", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "id", - is_optional: false, - is_list: false, - description: Some( - "File ids, separated by \\", - ), - type_description: None, - }, - ), - Number( - TypeInfo { - name: "priority", - is_optional: false, - is_list: false, - description: Some( - "File priority to set (consult [torrent contents API](#get-torrent-contents) for possible values)", - ), - type_description: None, - }, - ), - ], - ), - return_type: None, - url: "filePrio", - }, - ApiMethod { - name: "downloadLimit", - description: None, - parameters: None, - return_type: None, - url: "downloadLimit", - }, - ApiMethod { - name: "setShareLimits", - description: None, - parameters: None, - return_type: None, - url: "setShareLimits", - }, - ApiMethod { - name: "uploadLimit", - description: None, - parameters: None, - return_type: None, - url: "uploadLimit", - }, - ApiMethod { - name: "setUploadLimit", - description: None, - parameters: None, - return_type: None, - url: "setUploadLimit", - }, - ApiMethod { - name: "setLocation", - description: None, - parameters: None, - return_type: None, - url: "setLocation", - }, - ApiMethod { - name: "rename", - description: None, - parameters: None, - return_type: None, - url: "rename", - }, - ApiMethod { - name: "setCategory", - description: None, - parameters: None, - return_type: None, - url: "setCategory", - }, - ApiMethod { - name: "categories", - description: None, - parameters: None, - return_type: None, - url: "categories", - }, - ApiMethod { - name: "createCategory", - description: None, - parameters: None, - return_type: None, - url: "createCategory", - }, - ApiMethod { - name: "editCategory", - description: None, - parameters: None, - return_type: None, - url: "editCategory", - }, - ApiMethod { - name: "removeCategories", - description: None, - parameters: None, - return_type: None, - url: "removeCategories", - }, - ApiMethod { - name: "addTags", - description: None, - parameters: None, - return_type: None, - url: "addTags", - }, - ApiMethod { - name: "removeTags", - description: None, - parameters: None, - return_type: None, - url: "removeTags", - }, - ApiMethod { - name: "tags", - description: None, - parameters: None, - return_type: None, - url: "tags", - }, - ApiMethod { - name: "createTags", - description: None, - parameters: None, - return_type: None, - url: "createTags", - }, - ApiMethod { - name: "deleteTags", - description: None, - parameters: None, - return_type: None, - url: "deleteTags", - }, - ApiMethod { - name: "setAutoManagement", - description: None, - parameters: None, - return_type: None, - url: "setAutoManagement", - }, - ApiMethod { - name: "toggleSequentialDownload", - description: None, - parameters: Some( - [ - String( - TypeInfo { - name: "hashes", - is_optional: false, - is_list: false, - description: Some( - "The hashes of the torrents you want to toggle sequential download for. hashes can contain multiple hashes separated by \\", - ), - type_description: None, - }, - ), - ], - ), - return_type: None, - url: "toggleSequentialDownload", - }, - ApiMethod { - name: "toggleFirstLastPiecePrio", - description: None, - parameters: Some( - [ - String( - TypeInfo { - name: "hashes", - is_optional: false, - is_list: false, - description: Some( - "The hashes of the torrents you want to toggle the first/last piece priority for. hashes can contain multiple hashes separated by \\", - ), - type_description: None, - }, - ), - ], - ), - return_type: None, - url: "toggleFirstLastPiecePrio", - }, - ApiMethod { - name: "setForceStart", - description: None, - parameters: None, - return_type: None, - url: "setForceStart", - }, - ApiMethod { - name: "setSuperSeeding", - description: None, - parameters: None, - return_type: None, - url: "setSuperSeeding", - }, - ApiMethod { - name: "renameFile", - description: None, - parameters: Some( - [ - String( - TypeInfo { - name: "hash", - is_optional: false, - is_list: false, - description: Some( - "The hash of the torrent", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "oldPath", - is_optional: false, - is_list: false, - description: Some( - "The old path of the torrent", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "newPath", - is_optional: false, - is_list: false, - description: Some( - "The new path to use for the file", - ), - type_description: None, - }, - ), - ], - ), - return_type: None, - url: "renameFile", - }, - ApiMethod { - name: "renameFolder", - description: None, - parameters: Some( - [ - String( - TypeInfo { - name: "hash", - is_optional: false, - is_list: false, - description: Some( - "The hash of the torrent", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "oldPath", - is_optional: false, - is_list: false, - description: Some( - "The old path of the torrent", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "newPath", - is_optional: false, - is_list: false, - description: Some( - "The new path to use for the file", - ), - type_description: None, - }, - ), - ], - ), - return_type: None, - url: "renameFolder", - }, - ], - description: Some( - "All Torrent management API methods are under \"torrents\", e.g.: `/api/v2/torrents/methodName`.", - ), - url: "torrents", - }, - ApiGroup { - name: "rss", - methods: [ - ApiMethod { - name: "addFolder", - description: None, - parameters: Some( - [ - String( - TypeInfo { - name: "path", - is_optional: false, - is_list: false, - description: Some( - "Full path of added folder (e.g. \"The Pirate Bay\\Top100\")", - ), - type_description: None, - }, - ), - ], - ), - return_type: None, - url: "addFolder", - }, - ApiMethod { - name: "addFeed", - description: None, - parameters: Some( - [ - String( - TypeInfo { - name: "url", - is_optional: false, - is_list: false, - description: Some( - "URL of RSS feed (e.g. \"[http://thepiratebay.org/rss//top100/200](http://thepiratebay.org/rss//top100/200)\")", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "path", - is_optional: true, - is_list: false, - description: Some( - "Full path of added folder (e.g. \"The Pirate Bay\\Top100\\Video\")", - ), - type_description: None, - }, - ), - ], - ), - return_type: None, - url: "addFeed", - }, - ApiMethod { - name: "removeItem", - description: None, - parameters: Some( - [ - String( - TypeInfo { - name: "path", - is_optional: false, - is_list: false, - description: Some( - "Full path of removed item (e.g. \"The Pirate Bay\\Top100\")", - ), - type_description: None, - }, - ), - ], - ), - return_type: None, - url: "removeItem", - }, - ApiMethod { - name: "moveItem", - description: None, - parameters: Some( - [ - String( - TypeInfo { - name: "itemPath", - is_optional: false, - is_list: false, - description: Some( - "Current full path of item (e.g. \"The Pirate Bay\\Top100\")", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "destPath", - is_optional: false, - is_list: false, - description: Some( - "New full path of item (e.g. \"The Pirate Bay\")", - ), - type_description: None, - }, - ), - ], - ), - return_type: None, - url: "moveItem", - }, - ApiMethod { - name: "items", - description: None, - parameters: Some( - [ - Bool( - TypeInfo { - name: "withData", - is_optional: true, - is_list: false, - description: Some( - "True if you need current feed articles", - ), - type_description: None, - }, - ), - ], - ), - return_type: None, - url: "items", - }, - ApiMethod { - name: "markAsRead", - description: None, - parameters: Some( - [ - String( - TypeInfo { - name: "itemPath", - is_optional: false, - is_list: false, - description: Some( - "Current full path of item (e.g. \"The Pirate Bay\\Top100\")", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "articleId", - is_optional: true, - is_list: false, - description: Some( - "ID of article", - ), - type_description: None, - }, - ), - ], - ), - return_type: None, - url: "markAsRead", - }, - ApiMethod { - name: "refreshItem", - description: None, - parameters: Some( - [ - String( - TypeInfo { - name: "itemPath", - is_optional: false, - is_list: false, - description: Some( - "Current full path of item (e.g. \"The Pirate Bay\\Top100\")", - ), - type_description: None, - }, - ), - ], - ), - return_type: None, - url: "refreshItem", - }, - ApiMethod { - name: "setRule", - description: None, - parameters: Some( - [ - String( - TypeInfo { - name: "ruleName", - is_optional: false, - is_list: false, - description: Some( - "Rule name (e.g. \"Punisher\")", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "ruleDef", - is_optional: false, - is_list: false, - description: Some( - "JSON encoded rule definition", - ), - type_description: None, - }, - ), - ], - ), - return_type: None, - url: "setRule", - }, - ApiMethod { - name: "renameRule", - description: None, - parameters: Some( - [ - String( - TypeInfo { - name: "ruleName", - is_optional: false, - is_list: false, - description: Some( - "Rule name (e.g. \"Punisher\")", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "newRuleName", - is_optional: false, - is_list: false, - description: Some( - "New rule name (e.g. \"The Punisher\")", - ), - type_description: None, - }, - ), - ], - ), - return_type: None, - url: "renameRule", - }, - ApiMethod { - name: "removeRule", - description: None, - parameters: Some( - [ - String( - TypeInfo { - name: "ruleName", - is_optional: false, - is_list: false, - description: Some( - "Rule name (e.g. \"Punisher\")", - ), - type_description: None, - }, - ), - ], - ), - return_type: None, - url: "removeRule", - }, - ApiMethod { - name: "rules", - description: None, - parameters: None, - return_type: None, - url: "rules", - }, - ApiMethod { - name: "matchingArticles", - description: None, - parameters: None, - return_type: None, - url: "matchingArticles", - }, - ], - description: Some( - "All RSS API methods are under \"rss\", e.g.: `/api/v2/rss/methodName`.", - ), - url: "rss", - }, - ApiGroup { - name: "search", - methods: [ - ApiMethod { - name: "start", - description: Some( - "Example:\n\n```JSON\n{\n \"id\": 12345\n}\n```", - ), - parameters: Some( - [ - String( - TypeInfo { - name: "pattern", - is_optional: false, - is_list: false, - description: Some( - "Pattern to search for (e.g. \"Ubuntu 18.04\")", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "plugins", - is_optional: false, - is_list: false, - description: Some( - "Plugins to use for searching (e.g. \"legittorrents\"). Supports multiple plugins separated by \\", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "category", - is_optional: false, - is_list: false, - description: Some( - "Categories to limit your search to (e.g. \"legittorrents\"). Available categories depend on the specified plugins. Also supports all", - ), - type_description: None, - }, - ), - ], - ), - return_type: Some( - ReturnType { - is_list: false, - parameters: [ - ReturnTypeParameter { - name: "id", - description: "ID of the search job", - return_type: Number( - TypeInfo { - name: "id", - is_optional: false, - is_list: false, - description: Some( - "ID of the search job", - ), - type_description: None, - }, - ), - }, - ], - }, - ), - url: "start", - }, - ApiMethod { - name: "stop", - description: None, - parameters: Some( - [ - Number( - TypeInfo { - name: "id", - is_optional: false, - is_list: false, - description: Some( - "ID of the search job", - ), - type_description: None, - }, - ), - ], - ), - return_type: None, - url: "stop", - }, - ApiMethod { - name: "status", - description: Some( - "Example:\n\n```JSON\n[\n {\n \"id\": 12345,\n \"status\": \"Running\",\n \"total\": 170\n }\n]\n```", - ), - parameters: Some( - [ - Number( - TypeInfo { - name: "id", - is_optional: true, - is_list: false, - description: Some( - "ID of the search job. If not specified, all search jobs are returned", - ), - type_description: None, - }, - ), - ], - ), - return_type: Some( - ReturnType { - is_list: true, - parameters: [ - ReturnTypeParameter { - name: "id", - description: "ID of the search job", - return_type: Number( - TypeInfo { - name: "id", - is_optional: false, - is_list: false, - description: Some( - "ID of the search job", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "status", - description: "Current status of the search job (either Running or Stopped)", - return_type: String( - TypeInfo { - name: "status", - is_optional: false, - is_list: false, - description: Some( - "Current status of the search job (either Running or Stopped)", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "total", - description: "Total number of results. If the status is Running this number may contineu to increase", - return_type: Number( - TypeInfo { - name: "total", - is_optional: false, - is_list: false, - description: Some( - "Total number of results. If the status is Running this number may contineu to increase", - ), - type_description: None, - }, - ), - }, - ], - }, - ), - url: "status", - }, - ApiMethod { - name: "results", - description: None, - parameters: Some( - [ - Number( - TypeInfo { - name: "id", - is_optional: false, - is_list: false, - description: Some( - "ID of the search job", - ), - type_description: None, - }, - ), - Number( - TypeInfo { - name: "limit", - is_optional: true, - is_list: false, - description: Some( - "max number of results to return. 0 or negative means no limit", - ), - type_description: None, - }, - ), - Number( - TypeInfo { - name: "offset", - is_optional: true, - is_list: false, - description: Some( - "result to start at. A negative number means count backwards (e.g. -2 returns the 2 most recent results)", - ), - type_description: None, - }, - ), - ], - ), - return_type: Some( - ReturnType { - is_list: false, - parameters: [], - }, - ), - url: "results", - }, - ], - description: Some( - "All Search API methods are under \"search\", e.g.: `/api/v2/search/methodName`.", - ), - url: "search", - }, -] \ No newline at end of file diff --git a/qbittorrent-web-api-gen/src/parser/token_tree.txt b/qbittorrent-web-api-gen/src/parser/token_tree.txt deleted file mode 100644 index 52bd36c..0000000 --- a/qbittorrent-web-api-gen/src/parser/token_tree.txt +++ /dev/null @@ -1,13793 +0,0 @@ -TokenTree { - title: None, - content: [ - Text( - "This WebUI API documentation applies to qBittorrent v4.1+. For other WebUI API versions, visit [WebUI API](https://github.com/qbittorrent/qBittorrent/wiki#WebUI-API).", - ), - Text( - "", - ), - ], - children: [ - TokenTree { - title: Some( - "Table of Contents", - ), - content: [ - Text( - "", - ), - Text( - "1. [Changes](#changes)", - ), - Text( - " 1. [API v2.0](#api-v20)", - ), - Text( - " 1. [API v2.0.1](#api-v201)", - ), - Text( - " 1. [API v2.0.2](#api-v202)", - ), - Text( - " 1. [API v2.1.0](#api-v210)", - ), - Text( - " 1. [API v2.1.1](#api-v211)", - ), - Text( - " 1. [API v2.2.0](#api-v220)", - ), - Text( - " 1. [API v2.2.1](#api-v221)", - ), - Text( - " 1. [API v2.3.0](#api-v230)", - ), - Text( - " 1. [API v2.4.0](#api-v240)", - ), - Text( - " 1. [API v2.4.1](#api-v241)", - ), - Text( - " 1. [API v2.5.0](#api-v250)", - ), - Text( - " 1. [API v2.5.1](#api-v251)", - ), - Text( - " 1. [API v2.6.0](#api-v260)", - ), - Text( - " 1. [API v2.6.1](#api-v261)", - ), - Text( - " 1. [API v2.6.2](#api-v262)", - ), - Text( - " 1. [API v2.7.0](#api-v270)", - ), - Text( - " 1. [API v2.8.0](#api-v280)", - ), - Text( - " 1. [API v2.8.1](#api-v281)", - ), - Text( - " 1. [API v2.8.2](#api-v282)", - ), - Text( - " 1. [API v2.8.3](#api-v283)", - ), - Text( - "1. [General information](#general-information)", - ), - Text( - "1. [Authentication](#authentication)", - ), - Text( - " 1. [Login](#login)", - ), - Text( - " 1. [Logout](#logout)", - ), - Text( - "1. [Application](#application)", - ), - Text( - " 1. [Get application version](#get-application-version)", - ), - Text( - " 1. [Get API version](#get-api-version)", - ), - Text( - " 1. [Get build info](#get-build-info)", - ), - Text( - " 1. [Shutdown application](#shutdown-application)", - ), - Text( - " 1. [Get application preferences](#get-application-preferences)", - ), - Text( - " 1. [Set application preferences](#set-application-preferences)", - ), - Text( - " 1. [Get default save path](#get-default-save-path)", - ), - Text( - "1. [Log](#log)", - ), - Text( - " 1. [Get log](#get-log)", - ), - Text( - " 1. [Get peer log](#get-peer-log)", - ), - Text( - "1. [Sync](#sync)", - ), - Text( - " 1. [Get main data](#get-main-data)", - ), - Text( - " 1. [Get torrent peers data](#get-torrent-peers-data)", - ), - Text( - "1. [Transfer info](#transfer-info)", - ), - Text( - " 1. [Get global transfer info](#get-global-transfer-info)", - ), - Text( - " 1. [Get alternative speed limits state](#get-alternative-speed-limits-state)", - ), - Text( - " 1. [Toggle alternative speed limits](#toggle-alternative-speed-limits)", - ), - Text( - " 1. [Get global download limit](#get-global-download-limit)", - ), - Text( - " 1. [Set global download limit](#set-global-download-limit)", - ), - Text( - " 1. [Get global upload limit](#get-global-upload-limit)", - ), - Text( - " 1. [Set global upload limit](#set-global-upload-limit)", - ), - Text( - " 1. [Ban peers](#ban-peers)", - ), - Text( - "1. [Torrent management](#torrent-management)", - ), - Text( - " 1. [Get torrent list](#get-torrent-list)", - ), - Text( - " 1. [Get torrent generic properties](#get-torrent-generic-properties)", - ), - Text( - " 1. [Get torrent trackers](#get-torrent-trackers)", - ), - Text( - " 1. [Get torrent web seeds](#get-torrent-web-seeds)", - ), - Text( - " 1. [Get torrent contents](#get-torrent-contents)", - ), - Text( - " 1. [Get torrent pieces' states](#get-torrent-pieces-states)", - ), - Text( - " 1. [Get torrent pieces' hashes](#get-torrent-pieces-hashes)", - ), - Text( - " 1. [Pause torrents](#pause-torrents)", - ), - Text( - " 1. [Resume torrents](#resume-torrents)", - ), - Text( - " 1. [Delete torrents](#delete-torrents)", - ), - Text( - " 1. [Recheck torrents](#recheck-torrents)", - ), - Text( - " 1. [Reannounce torrents](#reannounce-torrents)", - ), - Text( - " 1. [Edit trackers](#edit-trackers)", - ), - Text( - " 1. [Remove trackers](#remove-trackers)", - ), - Text( - " 1. [Add peers](#add-peers)", - ), - Text( - " 1. [Add new torrent](#add-new-torrent)", - ), - Text( - " 1. [Add trackers to torrent](#add-trackers-to-torrent)", - ), - Text( - " 1. [Increase torrent priority](#increase-torrent-priority)", - ), - Text( - " 1. [Decrease torrent priority](#decrease-torrent-priority)", - ), - Text( - " 1. [Maximal torrent priority](#maximal-torrent-priority)", - ), - Text( - " 1. [Minimal torrent priority](#minimal-torrent-priority)", - ), - Text( - " 1. [Set file priority](#set-file-priority)", - ), - Text( - " 1. [Get torrent download limit](#get-torrent-download-limit)", - ), - Text( - " 1. [Set torrent download limit](#set-torrent-download-limit)", - ), - Text( - " 1. [Set torrent share limit](#set-torrent-share-limit)", - ), - Text( - " 1. [Get torrent upload limit](#get-torrent-upload-limit)", - ), - Text( - " 1. [Set torrent upload limit](#set-torrent-upload-limit)", - ), - Text( - " 1. [Set torrent location](#set-torrent-location)", - ), - Text( - " 1. [Set torrent name](#set-torrent-name)", - ), - Text( - " 1. [Set torrent category](#set-torrent-category)", - ), - Text( - " 1. [Get all categories](#get-all-categories)", - ), - Text( - " 1. [Add new category](#add-new-category)", - ), - Text( - " 1. [Edit category](#edit-category)", - ), - Text( - " 1. [Remove categories](#remove-categories)", - ), - Text( - " 1. [Add torrent tags](#add-torrent-tags)", - ), - Text( - " 1. [Remove torrent tags](#remove-torrent-tags)", - ), - Text( - " 1. [Get all tags](#get-all-tags)", - ), - Text( - " 1. [Create tags](#create-tags)", - ), - Text( - " 1. [Delete tags](#delete-tags)", - ), - Text( - " 1. [Set automatic torrent management](#set-automatic-torrent-management)", - ), - Text( - " 1. [Toggle sequential download](#toggle-sequential-download)", - ), - Text( - " 1. [Set first/last piece priority](#set-firstlast-piece-priority)", - ), - Text( - " 1. [Set force start](#set-force-start)", - ), - Text( - " 1. [Set super seeding](#set-super-seeding)", - ), - Text( - " 1. [Rename file](#rename-file)", - ), - Text( - " 1. [Rename folder](#rename-folder)", - ), - Text( - "1. [RSS (experimental)](#rss-experimental)", - ), - Text( - " 1. [Add folder](#add-folder)", - ), - Text( - " 1. [Add feed](#add-feed)", - ), - Text( - " 1. [Remove item](#remove-item)", - ), - Text( - " 1. [Move item](#move-item)", - ), - Text( - " 1. [Get all items](#get-all-items)", - ), - Text( - " 1. [Mark as read](#mark-as-read)", - ), - Text( - " 1. [Refresh item](#refresh-item)", - ), - Text( - " 1. [Set auto-downloading rule](#set-auto-downloading-rule)", - ), - Text( - " 1. [Rename auto-downloading rule](#rename-auto-downloading-rule)", - ), - Text( - " 1. [Remove auto-downloading rule](#remove-auto-downloading-rule)", - ), - Text( - " 1. [Get all auto-downloading rules](#get-all-auto-downloading-rules)", - ), - Text( - " 1. [Get all articles matching a rule](#get-all-articles-matching-a-rule)", - ), - Text( - "1. [Search](#search)", - ), - Text( - " 1. [Start search](#start-search)", - ), - Text( - " 1. [Stop search](#stop-search)", - ), - Text( - " 1. [Get search status](#get-search-status)", - ), - Text( - " 1. [Get search results](#get-search-results)", - ), - Text( - " 1. [Delete search](#delete-search)", - ), - Text( - " 1. [Get search plugins](#get-search-plugins)", - ), - Text( - " 1. [Install search plugin](#install-search-plugin)", - ), - Text( - " 1. [Uninstall search plugin](#uninstall-search-plugin)", - ), - Text( - " 1. [Enable search plugin](#enable-search-plugin)", - ), - Text( - " 1. [Update search plugins](#update-search-plugins)", - ), - Text( - "1. [WebAPI versioning](#webapi-versioning)", - ), - Text( - "", - ), - Asterix( - "", - ), - Text( - "", - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Changes", - ), - content: [ - Text( - "", - ), - ], - children: [ - TokenTree { - title: Some( - "API v2.0", - ), - content: [ - Text( - "", - ), - Text( - "- New version naming scheme: X.Y.Z (where X - major version, Y - minor version, Z - release version)", - ), - Text( - "- New API paths. All API methods are under `api/vX/` (where X is API major version)", - ), - Text( - "- API methods are under new scopes", - ), - Text( - "", - ), - ], - children: [], - }, - TokenTree { - title: Some( - "API v2.0.1", - ), - content: [ - Text( - "", - ), - Text( - "- Add `hashes` field to `/torrents/info` ([#8782](https://github.com/qbittorrent/qBittorrent/pull/8782))", - ), - Text( - "- Add `/torrents/setShareLimits/` method ([#8598](https://github.com/qbittorrent/qBittorrent/pull/8598))", - ), - Text( - "", - ), - ], - children: [], - }, - TokenTree { - title: Some( - "API v2.0.2", - ), - content: [ - Text( - "", - ), - Text( - "- Add `/torrents/reannounce` method ([#9229](https://github.com/qbittorrent/qBittorrent/pull/9229))", - ), - Text( - "", - ), - ], - children: [], - }, - TokenTree { - title: Some( - "API v2.1.0", - ), - content: [ - Text( - "", - ), - Text( - "- Change `/sync/maindata` `categories` field from `array` to `object` ([#9228](https://github.com/qbittorrent/qBittorrent/pull/9228))", - ), - Text( - "- Add `savePath` field to `/torrents/createCategory` ([#9228](https://github.com/qbittorrent/qBittorrent/pull/9228)). This method now requires the category to already exist and will not create new categories.", - ), - Text( - "- Add `/torrents/editCategory` method ([#9228](https://github.com/qbittorrent/qBittorrent/pull/9228))", - ), - Text( - "", - ), - ], - children: [], - }, - TokenTree { - title: Some( - "API v2.1.1", - ), - content: [ - Text( - "", - ), - Text( - "- Add `/torrents/categories` method ([#9586](https://github.com/qbittorrent/qBittorrent/pull/9586))", - ), - Text( - "- Add `/search/` methods ([#8584](https://github.com/qbittorrent/qBittorrent/pull/8584))", - ), - Text( - "- Add `free_space_on_disk` field to `/sync/maindata` ([#8217](https://github.com/qbittorrent/qBittorrent/pull/8217))", - ), - Text( - "", - ), - ], - children: [], - }, - TokenTree { - title: Some( - "API v2.2.0", - ), - content: [ - Text( - "", - ), - Text( - "- Add `/torrents/editTracker` and `/torrents/removeTracker` methods ([#9375](https://github.com/qbittorrent/qBittorrent/pull/9375))", - ), - Text( - "- Add `tier`, `num_seeds`, `num_leeches`, and `num_downloaded` fields to `/torrents/trackers` ([#9375](https://github.com/qbittorrent/qBittorrent/pull/9375))", - ), - Text( - "- Change `status` field from translated string to an integer for `/torrents/trackers` ([#9375](https://github.com/qbittorrent/qBittorrent/pull/9375))", - ), - Text( - "- Change `/torrents/filePrio` `id` field to accept multiple ids ([#9541](https://github.com/qbittorrent/qBittorrent/pull/9541))", - ), - Text( - "- Throw additional errors for failed requests to `/torrents/filePrio` ([#9541](https://github.com/qbittorrent/qBittorrent/pull/9541))", - ), - Text( - "- Add `autoTMM` field to `/torrents/add` ([#9752](https://github.com/qbittorrent/qBittorrent/pull/9752))", - ), - Text( - "- Add various fields to `/app/getPreferences` and `/app/setPreferences` (`create_subfolder_enabled`, `start_paused_enabled`, `auto_delete_mode`, `preallocate_all`, `incomplete_files_ext`, `auto_tmm_enabled`, `torrent_changed_tmm_enabled`, `save_path_changed_tmm_enabled`, `category_changed_tmm_enabled`, `mail_notification_sender`, `limit_lan_peers`, `slow_torrent_dl_rate_threshold`, `slow_torrent_ul_rate_threshold`, `slow_torrent_inactive_timer`, `alternative_webui_enabled`, `alternative_webui_path`) ([#9752](https://github.com/qbittorrent/qBittorrent/pull/9752))", - ), - Text( - "", - ), - ], - children: [], - }, - TokenTree { - title: Some( - "API v2.2.1", - ), - content: [ - Text( - "", - ), - Text( - "- Add `rss/refreshItem` ([#11067](https://github.com/qbittorrent/qBittorrent/pull/11067))", - ), - Text( - "", - ), - ], - children: [], - }, - TokenTree { - title: Some( - "API v2.3.0", - ), - content: [ - Text( - "", - ), - Text( - "- Remove `web_ui_password` field from `/app/preferences`, this field is still writable in `/app/setPreferences` method ([#9942](https://github.com/qbittorrent/qBittorrent/pull/9942))", - ), - Text( - "- Add `/app/buildInfo` method ([#10096](https://github.com/qbittorrent/qBittorrent/pull/10096))", - ), - Text( - "- Always use `/` as path separator in `/torrents/files` response ([#10153](https://github.com/qbittorrent/qBittorrent/pull/10153/))", - ), - Text( - "- Add `/torrents/addPeers` and `/transfer/banPeers` methods ([#10158](https://github.com/qbittorrent/qBittorrent/pull/10158))", - ), - Text( - "- Add `/torrents/addTags`, `/torrents/removeTags`, `/torrents/tags`, `/torrents/createTags`, `/torrents/deleteTags` methods ([#10527](https://github.com/qbittorrent/qBittorrent/pull/10527))", - ), - Text( - "", - ), - ], - children: [], - }, - TokenTree { - title: Some( - "API v2.4.0", - ), - content: [ - Text( - "", - ), - Text( - "- Add `/torrents/renameFile` method ([#11029](https://github.com/qbittorrent/qBittorrent/pull/11029))", - ), - Text( - "", - ), - ], - children: [], - }, - TokenTree { - title: Some( - "API v2.4.1", - ), - content: [ - Text( - "", - ), - Text( - "- Add `stalled`, `stalled_uploading` and `stalled_downloading` as possible values for the `filter` parameter in `/torrents/info` ([#11825](https://github.com/qbittorrent/qBittorrent/pull/11825))", - ), - Text( - "- Add various fields to `/app/preferences` and `/app/setPreferences` (`piece_extent_affinity`, `web_ui_secure_cookie_enabled`, `web_ui_max_auth_fail_count`, `web_ui_ban_duration`, `stop_tracker_timeout`) ([#11781](https://github.com/qbittorrent/qBittorrent/pull/11781), [#11726](https://github.com/qbittorrent/qBittorrent/pull/11726), [#12004](https://github.com/qbittorrent/qBittorrent/pull/12004), [#11834](https://github.com/qbittorrent/qBittorrent/pull/11834))", - ), - Text( - "", - ), - ], - children: [], - }, - TokenTree { - title: Some( - "API v2.5.0", - ), - content: [ - Text( - "- Removes `enable_super_seeding` as fields from `/app/preferences` and `/app/setPreferences` ([#12423](https://github.com/qbittorrent/qBittorrent/pull/12423))", - ), - Text( - "", - ), - ], - children: [], - }, - TokenTree { - title: Some( - "API v2.5.1", - ), - content: [ - Text( - "- Add `web_ui_use_custom_http_headers_enabled`, `web_ui_custom_http_headers`, `rss_download_repack_proper_episodes` and `rss_smart_episode_filters` as fields to `/app/preferences` and `/app/setPreferences` ([#12579](https://github.com/qbittorrent/qBittorrent/pull/12579), [#12549](https://github.com/qbittorrent/qBittorrent/pull/12549))", - ), - Text( - "- Add `/rss/markAsRead` and `/rss/matchingArticles` methods ([#12549](https://github.com/qbittorrent/qBittorrent/pull/12549))", - ), - Text( - "", - ), - ], - children: [], - }, - TokenTree { - title: Some( - "API v2.6.0", - ), - content: [ - Text( - "- Removed `/search/categories` method and modified `/search/plugins` method's response ([#12705](https://github.com/qbittorrent/qBittorrent/pull/12705))", - ), - Text( - "", - ), - ], - children: [], - }, - TokenTree { - title: Some( - "API v2.6.1", - ), - content: [ - Text( - "- Exposed `contentPath` via the `content_path` field in the response to `/torrents/info` ([#13625](https://github.com/qbittorrent/qBittorrent/pull/13625))", - ), - Text( - "", - ), - ], - children: [], - }, - TokenTree { - title: Some( - "API v2.6.2", - ), - content: [ - Text( - "- Added `tags` optional field to `/torrents/add` ([#13882](https://github.com/qbittorrent/qBittorrent/pull/13882))", - ), - Text( - "", - ), - ], - children: [], - }, - TokenTree { - title: Some( - "API v2.8.0", - ), - content: [ - Text( - "- Added `/torrents/renameFolder` method and modified `/torrents/renameFile` method's parameters ([#13995](https://github.com/qbittorrent/qBittorrent/pull/13995))", - ), - Text( - "", - ), - Text( - "Note that this change was released in qBittorrent v4.3.3, but the WebAPI version was incorrectly set to v2.7.0 (see [#14275](https://github.com/qbittorrent/qBittorrent/pull/14275#issuecomment-766310862) for details)", - ), - Text( - "", - ), - ], - children: [], - }, - TokenTree { - title: Some( - "API v2.8.1", - ), - content: [ - Text( - "- Added `ratioLimit` and `seedingTimeLimit` optional fields to `/torrents/add` ([#14519](https://github.com/qbittorrent/qBittorrent/pull/14519))", - ), - Text( - "- Added `seeding_time` field to `/torrents/info` ([#14554](https://github.com/qbittorrent/qBittorrent/pull/14554))", - ), - Text( - "", - ), - ], - children: [], - }, - TokenTree { - title: Some( - "API v2.8.2", - ), - content: [ - Text( - "- Added `indexes` optional parameter to `/torrents/files` ([#14795](https://github.com/qbittorrent/qBittorrent/pull/14795))", - ), - Text( - "- Added `index` field to `/torrents/files` response ([#14795](https://github.com/qbittorrent/qBittorrent/pull/14795))", - ), - Text( - "", - ), - ], - children: [], - }, - TokenTree { - title: Some( - "API v2.8.3", - ), - content: [ - Text( - "- Added `tag` optional parameter to `/torrents/info` ([#15152](https://github.com/qbittorrent/qBittorrent/pull/15152))", - ), - Text( - "", - ), - ], - children: [], - }, - ], - }, - TokenTree { - title: Some( - "General Information", - ), - content: [ - Text( - "", - ), - Text( - "- All API methods are under `/api/v2/APIName/methodName`, where `APIName` is a certain subgroup of API methods whose functionality is related.", - ), - Text( - "- Either `GET` or `POST` can be used as the request type for all API methods.", - ), - Text( - "- All API methods require [authentication](#authentication) (except the `/api/v2/auth/login` method itself, obviously).", - ), - Text( - "", - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Authentication", - ), - content: [ - Text( - "", - ), - Text( - "All Authentication API methods are under \"auth\", e.g.: `/api/v2/auth/methodName`.", - ), - Text( - "", - ), - Text( - "qBittorrent uses cookie-based authentication.", - ), - Text( - "", - ), - ], - children: [ - TokenTree { - title: Some( - "Login", - ), - content: [ - Text( - "", - ), - Text( - "Name: `login`", - ), - Text( - "", - ), - Asterix( - "Parameters:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Parameter | Type | Description", - columns: [ - "Parameter", - "Type", - "Description", - ], - }, - split: "----------------------------------|---------|------------", - rows: [ - TableRow { - raw: "`username` | string | Username used to access the WebUI", - columns: [ - "username", - "string", - "Username used to access the WebUI", - ], - }, - TableRow { - raw: "`password` | string | Password used to access the WebUI", - columns: [ - "password", - "string", - "Password used to access the WebUI", - ], - }, - ], - }, - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "403 | User's IP is banned for too many failed login attempts", - columns: [ - "403", - "User's IP is banned for too many failed login attempts", - ], - }, - TableRow { - raw: "200 | All other scenarios", - columns: [ - "200", - "All other scenarios", - ], - }, - ], - }, - ), - Text( - "Upon success, the response will contain a cookie with your SID. You must supply the cookie whenever you want to perform an operation that requires authentication.", - ), - Text( - "", - ), - Text( - "Example showing how to login and execute a command that requires authentication using `curl`:", - ), - Text( - "", - ), - Text( - "```sh", - ), - Text( - "$ curl -i --header 'Referer: http://localhost:8080' --data 'username=admin&password=adminadmin' http://localhost:8080/api/v2/auth/login", - ), - Text( - "HTTP/1.1 200 OK", - ), - Text( - "Content-Encoding:", - ), - Text( - "Content-Length: 3", - ), - Text( - "Content-Type: text/plain; charset=UTF-8", - ), - Text( - "Set-Cookie: SID=hBc7TxF76ERhvIw0jQQ4LZ7Z1jQUV0tQ; path=/", - ), - Text( - "$ curl http://localhost:8080/api/v2/torrents/info --cookie \"SID=hBc7TxF76ERhvIw0jQQ4LZ7Z1jQUV0tQ\"", - ), - Text( - "```", - ), - Text( - "", - ), - Text( - "Note: Set `Referer` or `Origin` header to the exact same domain and port as used in the HTTP query `Host` header.", - ), - Text( - "", - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Logout", - ), - content: [ - Text( - "", - ), - Text( - "Name: `logout`", - ), - Text( - "", - ), - Asterix( - "Parameters:", - ), - Text( - "", - ), - Text( - "None", - ), - Text( - "", - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "200 | All scenarios", - columns: [ - "200", - "All scenarios", - ], - }, - ], - }, - ), - ], - children: [], - }, - ], - }, - TokenTree { - title: Some( - "Application", - ), - content: [ - Text( - "", - ), - Text( - "All Application API methods are under \"app\", e.g.: `/api/v2/app/methodName`.", - ), - Text( - "", - ), - ], - children: [ - TokenTree { - title: Some( - "Get application version", - ), - content: [ - Text( - "", - ), - Text( - "Name: `version`", - ), - Text( - "", - ), - Asterix( - "Parameters:", - ), - Text( - "", - ), - Text( - "None", - ), - Text( - "", - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "200 | All scenarios", - columns: [ - "200", - "All scenarios", - ], - }, - ], - }, - ), - Text( - "The response is a string with the application version, e.g. `v4.1.3`", - ), - Text( - "", - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Get API version", - ), - content: [ - Text( - "", - ), - Text( - "Name: `webapiVersion`", - ), - Text( - "", - ), - Asterix( - "Parameters:", - ), - Text( - "", - ), - Text( - "None", - ), - Text( - "", - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "200 | All scenarios", - columns: [ - "200", - "All scenarios", - ], - }, - ], - }, - ), - Text( - "The response is a string with the WebAPI version, e.g. `2.0`", - ), - Text( - "", - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Get build info", - ), - content: [ - Text( - "", - ), - Text( - "Name: `buildInfo`", - ), - Text( - "", - ), - Asterix( - "Parameters:", - ), - Text( - "", - ), - Text( - "None", - ), - Text( - "", - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "200 | All scenarios- see JSON below", - columns: [ - "200", - "All scenarios- see JSON below", - ], - }, - ], - }, - ), - Text( - "The response is a JSON object containing the following fields", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Property | Type | Description", - columns: [ - "Property", - "Type", - "Description", - ], - }, - split: "-------------|---------|------------", - rows: [ - TableRow { - raw: "`qt` | string | QT version", - columns: [ - "qt", - "string", - "QT version", - ], - }, - TableRow { - raw: "`libtorrent` | string | libtorrent version", - columns: [ - "libtorrent", - "string", - "libtorrent version", - ], - }, - TableRow { - raw: "`boost` | string | Boost version", - columns: [ - "boost", - "string", - "Boost version", - ], - }, - TableRow { - raw: "`openssl` | string | OpenSSL version", - columns: [ - "openssl", - "string", - "OpenSSL version", - ], - }, - TableRow { - raw: "`bitness` | int | Application bitness (e.g. 64-bit)", - columns: [ - "bitness", - "int", - "Application bitness (e.g. 64-bit)", - ], - }, - ], - }, - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Shutdown application", - ), - content: [ - Text( - "", - ), - Text( - "Name: `shutdown`", - ), - Text( - "", - ), - Asterix( - "Parameters:", - ), - Text( - "", - ), - Text( - "None", - ), - Text( - "", - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "200 | All scenarios", - columns: [ - "200", - "All scenarios", - ], - }, - ], - }, - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Get application preferences", - ), - content: [ - Text( - "", - ), - Text( - "Name: `preferences`", - ), - Text( - "", - ), - Asterix( - "Parameters:", - ), - Text( - "", - ), - Text( - "None", - ), - Text( - "", - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "200 | All scenarios- see JSON below", - columns: [ - "200", - "All scenarios- see JSON below", - ], - }, - ], - }, - ), - Text( - "The response is a JSON object with several fields (key-value) pairs representing the application's settings. The contents may vary depending on which settings are present in qBittorrent.ini.", - ), - Text( - "", - ), - Text( - "Possible fields:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Property | Type | Description", - columns: [ - "Property", - "Type", - "Description", - ], - }, - split: "-----------------------------------------|---------|------------", - rows: [ - TableRow { - raw: "`locale` | string | Currently selected language (e.g. en_GB for English)", - columns: [ - "locale", - "string", - "Currently selected language (e.g. en_GB for English)", - ], - }, - TableRow { - raw: "`create_subfolder_enabled` | bool | True if a subfolder should be created when adding a torrent", - columns: [ - "create_subfolder_enabled", - "bool", - "True if a subfolder should be created when adding a torrent", - ], - }, - TableRow { - raw: "`start_paused_enabled` | bool | True if torrents should be added in a Paused state", - columns: [ - "start_paused_enabled", - "bool", - "True if torrents should be added in a Paused state", - ], - }, - TableRow { - raw: "`auto_delete_mode` | integer | TODO", - columns: [ - "auto_delete_mode", - "integer", - "TODO", - ], - }, - TableRow { - raw: "`preallocate_all` | bool | True if disk space should be pre-allocated for all files", - columns: [ - "preallocate_all", - "bool", - "True if disk space should be pre-allocated for all files", - ], - }, - TableRow { - raw: "`incomplete_files_ext` | bool | True if \".!qB\" should be appended to incomplete files", - columns: [ - "incomplete_files_ext", - "bool", - "True if \".!qB\" should be appended to incomplete files", - ], - }, - TableRow { - raw: "`auto_tmm_enabled` | bool | True if Automatic Torrent Management is enabled by default", - columns: [ - "auto_tmm_enabled", - "bool", - "True if Automatic Torrent Management is enabled by default", - ], - }, - TableRow { - raw: "`torrent_changed_tmm_enabled` | bool | True if torrent should be relocated when its Category changes", - columns: [ - "torrent_changed_tmm_enabled", - "bool", - "True if torrent should be relocated when its Category changes", - ], - }, - TableRow { - raw: "`save_path_changed_tmm_enabled` | bool | True if torrent should be relocated when the default save path changes", - columns: [ - "save_path_changed_tmm_enabled", - "bool", - "True if torrent should be relocated when the default save path changes", - ], - }, - TableRow { - raw: "`category_changed_tmm_enabled` | bool | True if torrent should be relocated when its Category's save path changes", - columns: [ - "category_changed_tmm_enabled", - "bool", - "True if torrent should be relocated when its Category's save path changes", - ], - }, - TableRow { - raw: "`save_path` | string | Default save path for torrents, separated by slashes", - columns: [ - "save_path", - "string", - "Default save path for torrents, separated by slashes", - ], - }, - TableRow { - raw: "`temp_path_enabled` | bool | True if folder for incomplete torrents is enabled", - columns: [ - "temp_path_enabled", - "bool", - "True if folder for incomplete torrents is enabled", - ], - }, - TableRow { - raw: "`temp_path` | string | Path for incomplete torrents, separated by slashes", - columns: [ - "temp_path", - "string", - "Path for incomplete torrents, separated by slashes", - ], - }, - TableRow { - raw: "`scan_dirs` | object | Property: directory to watch for torrent files, value: where torrents loaded from this directory should be downloaded to (see list of possible values below). Slashes are used as path separators; multiple key/value pairs can be specified", - columns: [ - "scan_dirs", - "object", - "Property: directory to watch for torrent files, value: where torrents loaded from this directory should be downloaded to (see list of possible values below). Slashes are used as path separators; multiple key/value pairs can be specified", - ], - }, - TableRow { - raw: "`export_dir` | string | Path to directory to copy .torrent files to. Slashes are used as path separators", - columns: [ - "export_dir", - "string", - "Path to directory to copy .torrent files to. Slashes are used as path separators", - ], - }, - TableRow { - raw: "`export_dir_fin` | string | Path to directory to copy .torrent files of completed downloads to. Slashes are used as path separators", - columns: [ - "export_dir_fin", - "string", - "Path to directory to copy .torrent files of completed downloads to. Slashes are used as path separators", - ], - }, - TableRow { - raw: "`mail_notification_enabled` | bool | True if e-mail notification should be enabled", - columns: [ - "mail_notification_enabled", - "bool", - "True if e-mail notification should be enabled", - ], - }, - TableRow { - raw: "`mail_notification_sender` | string | e-mail where notifications should originate from", - columns: [ - "mail_notification_sender", - "string", - "e-mail where notifications should originate from", - ], - }, - TableRow { - raw: "`mail_notification_email` | string | e-mail to send notifications to", - columns: [ - "mail_notification_email", - "string", - "e-mail to send notifications to", - ], - }, - TableRow { - raw: "`mail_notification_smtp` | string | smtp server for e-mail notifications", - columns: [ - "mail_notification_smtp", - "string", - "smtp server for e-mail notifications", - ], - }, - TableRow { - raw: "`mail_notification_ssl_enabled` | bool | True if smtp server requires SSL connection", - columns: [ - "mail_notification_ssl_enabled", - "bool", - "True if smtp server requires SSL connection", - ], - }, - TableRow { - raw: "`mail_notification_auth_enabled` | bool | True if smtp server requires authentication", - columns: [ - "mail_notification_auth_enabled", - "bool", - "True if smtp server requires authentication", - ], - }, - TableRow { - raw: "`mail_notification_username` | string | Username for smtp authentication", - columns: [ - "mail_notification_username", - "string", - "Username for smtp authentication", - ], - }, - TableRow { - raw: "`mail_notification_password` | string | Password for smtp authentication", - columns: [ - "mail_notification_password", - "string", - "Password for smtp authentication", - ], - }, - TableRow { - raw: "`autorun_enabled` | bool | True if external program should be run after torrent has finished downloading", - columns: [ - "autorun_enabled", - "bool", - "True if external program should be run after torrent has finished downloading", - ], - }, - TableRow { - raw: "`autorun_program` | string | Program path/name/arguments to run if `autorun_enabled` is enabled; path is separated by slashes; you can use `%f` and `%n` arguments, which will be expanded by qBittorent as path_to_torrent_file and torrent_name (from the GUI; not the .torrent file name) respectively", - columns: [ - "autorun_program", - "string", - "Program path/name/arguments to run if autorun_enabled is enabled; path is separated by slashes; you can use %f and %n arguments, which will be expanded by qBittorent as path_to_torrent_file and torrent_name (from the GUI; not the .torrent file name) respectively", - ], - }, - TableRow { - raw: "`queueing_enabled` | bool | True if torrent queuing is enabled", - columns: [ - "queueing_enabled", - "bool", - "True if torrent queuing is enabled", - ], - }, - TableRow { - raw: "`max_active_downloads` | integer | Maximum number of active simultaneous downloads", - columns: [ - "max_active_downloads", - "integer", - "Maximum number of active simultaneous downloads", - ], - }, - TableRow { - raw: "`max_active_torrents` | integer | Maximum number of active simultaneous downloads and uploads", - columns: [ - "max_active_torrents", - "integer", - "Maximum number of active simultaneous downloads and uploads", - ], - }, - TableRow { - raw: "`max_active_uploads` | integer | Maximum number of active simultaneous uploads", - columns: [ - "max_active_uploads", - "integer", - "Maximum number of active simultaneous uploads", - ], - }, - TableRow { - raw: "`dont_count_slow_torrents` | bool | If true torrents w/o any activity (stalled ones) will not be counted towards `max_active_*` limits; see [dont_count_slow_torrents](https://www.libtorrent.org/reference-Settings.html#dont_count_slow_torrents) for more information", - columns: [ - "dont_count_slow_torrents", - "bool", - "If true torrents w/o any activity (stalled ones) will not be counted towards max_active_* limits; see [dont_count_slow_torrents](https://www.libtorrent.org/reference-Settings.html#dont_count_slow_torrents) for more information", - ], - }, - TableRow { - raw: "`slow_torrent_dl_rate_threshold` | integer | Download rate in KiB/s for a torrent to be considered \"slow\"", - columns: [ - "slow_torrent_dl_rate_threshold", - "integer", - "Download rate in KiB/s for a torrent to be considered \"slow\"", - ], - }, - TableRow { - raw: "`slow_torrent_ul_rate_threshold` | integer | Upload rate in KiB/s for a torrent to be considered \"slow\"", - columns: [ - "slow_torrent_ul_rate_threshold", - "integer", - "Upload rate in KiB/s for a torrent to be considered \"slow\"", - ], - }, - TableRow { - raw: "`slow_torrent_inactive_timer` | integer | Seconds a torrent should be inactive before considered \"slow\"", - columns: [ - "slow_torrent_inactive_timer", - "integer", - "Seconds a torrent should be inactive before considered \"slow\"", - ], - }, - TableRow { - raw: "`max_ratio_enabled` | bool | True if share ratio limit is enabled", - columns: [ - "max_ratio_enabled", - "bool", - "True if share ratio limit is enabled", - ], - }, - TableRow { - raw: "`max_ratio` | float | Get the global share ratio limit", - columns: [ - "max_ratio", - "float", - "Get the global share ratio limit", - ], - }, - TableRow { - raw: "`max_ratio_act` | integer | Action performed when a torrent reaches the maximum share ratio. See list of possible values here below.", - columns: [ - "max_ratio_act", - "integer", - "Action performed when a torrent reaches the maximum share ratio. See list of possible values here below.", - ], - }, - TableRow { - raw: "`listen_port` | integer | Port for incoming connections", - columns: [ - "listen_port", - "integer", - "Port for incoming connections", - ], - }, - TableRow { - raw: "`upnp` | bool | True if UPnP/NAT-PMP is enabled", - columns: [ - "upnp", - "bool", - "True if UPnP/NAT-PMP is enabled", - ], - }, - TableRow { - raw: "`random_port` | bool | True if the port is randomly selected", - columns: [ - "random_port", - "bool", - "True if the port is randomly selected", - ], - }, - TableRow { - raw: "`dl_limit` | integer | Global download speed limit in KiB/s; `-1` means no limit is applied", - columns: [ - "dl_limit", - "integer", - "Global download speed limit in KiB/s; -1 means no limit is applied", - ], - }, - TableRow { - raw: "`up_limit` | integer | Global upload speed limit in KiB/s; `-1` means no limit is applied", - columns: [ - "up_limit", - "integer", - "Global upload speed limit in KiB/s; -1 means no limit is applied", - ], - }, - TableRow { - raw: "`max_connec` | integer | Maximum global number of simultaneous connections", - columns: [ - "max_connec", - "integer", - "Maximum global number of simultaneous connections", - ], - }, - TableRow { - raw: "`max_connec_per_torrent` | integer | Maximum number of simultaneous connections per torrent", - columns: [ - "max_connec_per_torrent", - "integer", - "Maximum number of simultaneous connections per torrent", - ], - }, - TableRow { - raw: "`max_uploads` | integer | Maximum number of upload slots", - columns: [ - "max_uploads", - "integer", - "Maximum number of upload slots", - ], - }, - TableRow { - raw: "`max_uploads_per_torrent` | integer | Maximum number of upload slots per torrent", - columns: [ - "max_uploads_per_torrent", - "integer", - "Maximum number of upload slots per torrent", - ], - }, - TableRow { - raw: "`stop_tracker_timeout` | integer | Timeout in seconds for a `stopped` announce request to trackers", - columns: [ - "stop_tracker_timeout", - "integer", - "Timeout in seconds for a stopped announce request to trackers", - ], - }, - TableRow { - raw: "`enable_piece_extent_affinity` | bool | True if the advanced libtorrent option `piece_extent_affinity` is enabled", - columns: [ - "enable_piece_extent_affinity", - "bool", - "True if the advanced libtorrent option piece_extent_affinity is enabled", - ], - }, - TableRow { - raw: "`bittorrent_protocol` | integer | Bittorrent Protocol to use (see list of possible values below)", - columns: [ - "bittorrent_protocol", - "integer", - "Bittorrent Protocol to use (see list of possible values below)", - ], - }, - TableRow { - raw: "`limit_utp_rate` | bool | True if `[du]l_limit` should be applied to uTP connections; this option is only available in qBittorent built against libtorrent version 0.16.X and higher", - columns: [ - "limit_utp_rate", - "bool", - "True if [du]l_limit should be applied to uTP connections; this option is only available in qBittorent built against libtorrent version 0.16.X and higher", - ], - }, - TableRow { - raw: "`limit_tcp_overhead` | bool | True if `[du]l_limit` should be applied to estimated TCP overhead (service data: e.g. packet headers)", - columns: [ - "limit_tcp_overhead", - "bool", - "True if [du]l_limit should be applied to estimated TCP overhead (service data: e.g. packet headers)", - ], - }, - TableRow { - raw: "`limit_lan_peers` | bool | True if `[du]l_limit` should be applied to peers on the LAN", - columns: [ - "limit_lan_peers", - "bool", - "True if [du]l_limit should be applied to peers on the LAN", - ], - }, - TableRow { - raw: "`alt_dl_limit` | integer | Alternative global download speed limit in KiB/s", - columns: [ - "alt_dl_limit", - "integer", - "Alternative global download speed limit in KiB/s", - ], - }, - TableRow { - raw: "`alt_up_limit` | integer | Alternative global upload speed limit in KiB/s", - columns: [ - "alt_up_limit", - "integer", - "Alternative global upload speed limit in KiB/s", - ], - }, - TableRow { - raw: "`scheduler_enabled` | bool | True if alternative limits should be applied according to schedule", - columns: [ - "scheduler_enabled", - "bool", - "True if alternative limits should be applied according to schedule", - ], - }, - TableRow { - raw: "`schedule_from_hour` | integer | Scheduler starting hour", - columns: [ - "schedule_from_hour", - "integer", - "Scheduler starting hour", - ], - }, - TableRow { - raw: "`schedule_from_min` | integer | Scheduler starting minute", - columns: [ - "schedule_from_min", - "integer", - "Scheduler starting minute", - ], - }, - TableRow { - raw: "`schedule_to_hour` | integer | Scheduler ending hour", - columns: [ - "schedule_to_hour", - "integer", - "Scheduler ending hour", - ], - }, - TableRow { - raw: "`schedule_to_min` | integer | Scheduler ending minute", - columns: [ - "schedule_to_min", - "integer", - "Scheduler ending minute", - ], - }, - TableRow { - raw: "`scheduler_days` | integer | Scheduler days. See possible values here below", - columns: [ - "scheduler_days", - "integer", - "Scheduler days. See possible values here below", - ], - }, - TableRow { - raw: "`dht` | bool | True if DHT is enabled", - columns: [ - "dht", - "bool", - "True if DHT is enabled", - ], - }, - TableRow { - raw: "`pex` | bool | True if PeX is enabled", - columns: [ - "pex", - "bool", - "True if PeX is enabled", - ], - }, - TableRow { - raw: "`lsd` | bool | True if LSD is enabled", - columns: [ - "lsd", - "bool", - "True if LSD is enabled", - ], - }, - TableRow { - raw: "`encryption` | integer | See list of possible values here below", - columns: [ - "encryption", - "integer", - "See list of possible values here below", - ], - }, - TableRow { - raw: "`anonymous_mode` | bool | If true anonymous mode will be enabled; read more [here](Anonymous-Mode); this option is only available in qBittorent built against libtorrent version 0.16.X and higher", - columns: [ - "anonymous_mode", - "bool", - "If true anonymous mode will be enabled; read more [here](Anonymous-Mode); this option is only available in qBittorent built against libtorrent version 0.16.X and higher", - ], - }, - TableRow { - raw: "`proxy_type` | integer | See list of possible values here below", - columns: [ - "proxy_type", - "integer", - "See list of possible values here below", - ], - }, - TableRow { - raw: "`proxy_ip` | string | Proxy IP address or domain name", - columns: [ - "proxy_ip", - "string", - "Proxy IP address or domain name", - ], - }, - TableRow { - raw: "`proxy_port` | integer | Proxy port", - columns: [ - "proxy_port", - "integer", - "Proxy port", - ], - }, - TableRow { - raw: "`proxy_peer_connections` | bool | True if peer and web seed connections should be proxified; this option will have any effect only in qBittorent built against libtorrent version 0.16.X and higher", - columns: [ - "proxy_peer_connections", - "bool", - "True if peer and web seed connections should be proxified; this option will have any effect only in qBittorent built against libtorrent version 0.16.X and higher", - ], - }, - TableRow { - raw: "`proxy_auth_enabled` | bool | True proxy requires authentication; doesn't apply to SOCKS4 proxies", - columns: [ - "proxy_auth_enabled", - "bool", - "True proxy requires authentication; doesn't apply to SOCKS4 proxies", - ], - }, - TableRow { - raw: "`proxy_username` | string | Username for proxy authentication", - columns: [ - "proxy_username", - "string", - "Username for proxy authentication", - ], - }, - TableRow { - raw: "`proxy_password` | string | Password for proxy authentication", - columns: [ - "proxy_password", - "string", - "Password for proxy authentication", - ], - }, - TableRow { - raw: "`proxy_torrents_only` | bool | True if proxy is only used for torrents", - columns: [ - "proxy_torrents_only", - "bool", - "True if proxy is only used for torrents", - ], - }, - TableRow { - raw: "`ip_filter_enabled` | bool | True if external IP filter should be enabled", - columns: [ - "ip_filter_enabled", - "bool", - "True if external IP filter should be enabled", - ], - }, - TableRow { - raw: "`ip_filter_path` | string | Path to IP filter file (.dat, .p2p, .p2b files are supported); path is separated by slashes", - columns: [ - "ip_filter_path", - "string", - "Path to IP filter file (.dat, .p2p, .p2b files are supported); path is separated by slashes", - ], - }, - TableRow { - raw: "`ip_filter_trackers` | bool | True if IP filters are applied to trackers", - columns: [ - "ip_filter_trackers", - "bool", - "True if IP filters are applied to trackers", - ], - }, - TableRow { - raw: "`web_ui_domain_list` | string | Comma-separated list of domains to accept when performing Host header validation", - columns: [ - "web_ui_domain_list", - "string", - "Comma-separated list of domains to accept when performing Host header validation", - ], - }, - TableRow { - raw: "`web_ui_address` | string | IP address to use for the WebUI", - columns: [ - "web_ui_address", - "string", - "IP address to use for the WebUI", - ], - }, - TableRow { - raw: "`web_ui_port` | integer | WebUI port", - columns: [ - "web_ui_port", - "integer", - "WebUI port", - ], - }, - TableRow { - raw: "`web_ui_upnp` | bool | True if UPnP is used for the WebUI port", - columns: [ - "web_ui_upnp", - "bool", - "True if UPnP is used for the WebUI port", - ], - }, - TableRow { - raw: "`web_ui_username` | string | WebUI username", - columns: [ - "web_ui_username", - "string", - "WebUI username", - ], - }, - TableRow { - raw: "`web_ui_password` | string | For API ≥ v2.3.0: Plaintext WebUI password, not readable, write-only. For API < v2.3.0: MD5 hash of WebUI password, hash is generated from the following string: `username:Web UI Access:plain_text_web_ui_password`", - columns: [ - "web_ui_password", - "string", - "For API ≥ v2.3.0: Plaintext WebUI password, not readable, write-only. For API < v2.3.0: MD5 hash of WebUI password, hash is generated from the following string: username:Web UI Access:plain_text_web_ui_password", - ], - }, - TableRow { - raw: "`web_ui_csrf_protection_enabled` | bool | True if WebUI CSRF protection is enabled", - columns: [ - "web_ui_csrf_protection_enabled", - "bool", - "True if WebUI CSRF protection is enabled", - ], - }, - TableRow { - raw: "`web_ui_clickjacking_protection_enabled` | bool | True if WebUI clickjacking protection is enabled", - columns: [ - "web_ui_clickjacking_protection_enabled", - "bool", - "True if WebUI clickjacking protection is enabled", - ], - }, - TableRow { - raw: "`web_ui_secure_cookie_enabled` | bool | True if WebUI cookie `Secure` flag is enabled", - columns: [ - "web_ui_secure_cookie_enabled", - "bool", - "True if WebUI cookie Secure flag is enabled", - ], - }, - TableRow { - raw: "`web_ui_max_auth_fail_count` | integer | Maximum number of authentication failures before WebUI access ban", - columns: [ - "web_ui_max_auth_fail_count", - "integer", - "Maximum number of authentication failures before WebUI access ban", - ], - }, - TableRow { - raw: "`web_ui_ban_duration` | integer | WebUI access ban duration in seconds", - columns: [ - "web_ui_ban_duration", - "integer", - "WebUI access ban duration in seconds", - ], - }, - TableRow { - raw: "`web_ui_session_timeout` | integer | Seconds until WebUI is automatically signed off", - columns: [ - "web_ui_session_timeout", - "integer", - "Seconds until WebUI is automatically signed off", - ], - }, - TableRow { - raw: "`web_ui_host_header_validation_enabled` | bool | True if WebUI host header validation is enabled", - columns: [ - "web_ui_host_header_validation_enabled", - "bool", - "True if WebUI host header validation is enabled", - ], - }, - TableRow { - raw: "`bypass_local_auth` | bool | True if authentication challenge for loopback address (127.0.0.1) should be disabled", - columns: [ - "bypass_local_auth", - "bool", - "True if authentication challenge for loopback address (127.0.0.1) should be disabled", - ], - }, - TableRow { - raw: "`bypass_auth_subnet_whitelist_enabled` | bool | True if webui authentication should be bypassed for clients whose ip resides within (at least) one of the subnets on the whitelist", - columns: [ - "bypass_auth_subnet_whitelist_enabled", - "bool", - "True if webui authentication should be bypassed for clients whose ip resides within (at least) one of the subnets on the whitelist", - ], - }, - TableRow { - raw: "`bypass_auth_subnet_whitelist` | string | (White)list of ipv4/ipv6 subnets for which webui authentication should be bypassed; list entries are separated by commas", - columns: [ - "bypass_auth_subnet_whitelist", - "string", - "(White)list of ipv4/ipv6 subnets for which webui authentication should be bypassed; list entries are separated by commas", - ], - }, - TableRow { - raw: "`alternative_webui_enabled` | bool | True if an alternative WebUI should be used", - columns: [ - "alternative_webui_enabled", - "bool", - "True if an alternative WebUI should be used", - ], - }, - TableRow { - raw: "`alternative_webui_path` | string | File path to the alternative WebUI", - columns: [ - "alternative_webui_path", - "string", - "File path to the alternative WebUI", - ], - }, - TableRow { - raw: "`use_https` | bool | True if WebUI HTTPS access is enabled", - columns: [ - "use_https", - "bool", - "True if WebUI HTTPS access is enabled", - ], - }, - TableRow { - raw: "`ssl_key` | string | For API < v2.0.1: SSL keyfile contents (this is a not a path)", - columns: [ - "ssl_key", - "string", - "For API < v2.0.1: SSL keyfile contents (this is a not a path)", - ], - }, - TableRow { - raw: "`ssl_cert` | string | For API < v2.0.1: SSL certificate contents (this is a not a path)", - columns: [ - "ssl_cert", - "string", - "For API < v2.0.1: SSL certificate contents (this is a not a path)", - ], - }, - TableRow { - raw: "`web_ui_https_key_path` | string | For API ≥ v2.0.1: Path to SSL keyfile", - columns: [ - "web_ui_https_key_path", - "string", - "For API ≥ v2.0.1: Path to SSL keyfile", - ], - }, - TableRow { - raw: "`web_ui_https_cert_path` | string | For API ≥ v2.0.1: Path to SSL certificate", - columns: [ - "web_ui_https_cert_path", - "string", - "For API ≥ v2.0.1: Path to SSL certificate", - ], - }, - TableRow { - raw: "`dyndns_enabled` | bool | True if server DNS should be updated dynamically", - columns: [ - "dyndns_enabled", - "bool", - "True if server DNS should be updated dynamically", - ], - }, - TableRow { - raw: "`dyndns_service` | integer | See list of possible values here below", - columns: [ - "dyndns_service", - "integer", - "See list of possible values here below", - ], - }, - TableRow { - raw: "`dyndns_username` | string | Username for DDNS service", - columns: [ - "dyndns_username", - "string", - "Username for DDNS service", - ], - }, - TableRow { - raw: "`dyndns_password` | string | Password for DDNS service", - columns: [ - "dyndns_password", - "string", - "Password for DDNS service", - ], - }, - TableRow { - raw: "`dyndns_domain` | string | Your DDNS domain name", - columns: [ - "dyndns_domain", - "string", - "Your DDNS domain name", - ], - }, - TableRow { - raw: "`rss_refresh_interval` | integer | RSS refresh interval", - columns: [ - "rss_refresh_interval", - "integer", - "RSS refresh interval", - ], - }, - TableRow { - raw: "`rss_max_articles_per_feed` | integer | Max stored articles per RSS feed", - columns: [ - "rss_max_articles_per_feed", - "integer", - "Max stored articles per RSS feed", - ], - }, - TableRow { - raw: "`rss_processing_enabled` | bool | Enable processing of RSS feeds", - columns: [ - "rss_processing_enabled", - "bool", - "Enable processing of RSS feeds", - ], - }, - TableRow { - raw: "`rss_auto_downloading_enabled` | bool | Enable auto-downloading of torrents from the RSS feeds", - columns: [ - "rss_auto_downloading_enabled", - "bool", - "Enable auto-downloading of torrents from the RSS feeds", - ], - }, - TableRow { - raw: "`rss_download_repack_proper_episodes` | bool | For API ≥ v2.5.1: Enable downloading of repack/proper Episodes", - columns: [ - "rss_download_repack_proper_episodes", - "bool", - "For API ≥ v2.5.1: Enable downloading of repack/proper Episodes", - ], - }, - TableRow { - raw: "`rss_smart_episode_filters` | string | For API ≥ v2.5.1: List of RSS Smart Episode Filters", - columns: [ - "rss_smart_episode_filters", - "string", - "For API ≥ v2.5.1: List of RSS Smart Episode Filters", - ], - }, - TableRow { - raw: "`add_trackers_enabled` | bool | Enable automatic adding of trackers to new torrents", - columns: [ - "add_trackers_enabled", - "bool", - "Enable automatic adding of trackers to new torrents", - ], - }, - TableRow { - raw: "`add_trackers` | string | List of trackers to add to new torrent", - columns: [ - "add_trackers", - "string", - "List of trackers to add to new torrent", - ], - }, - TableRow { - raw: "`web_ui_use_custom_http_headers_enabled` | bool | For API ≥ v2.5.1: Enable custom http headers", - columns: [ - "web_ui_use_custom_http_headers_enabled", - "bool", - "For API ≥ v2.5.1: Enable custom http headers", - ], - }, - TableRow { - raw: "`web_ui_custom_http_headers` | string | For API ≥ v2.5.1: List of custom http headers", - columns: [ - "web_ui_custom_http_headers", - "string", - "For API ≥ v2.5.1: List of custom http headers", - ], - }, - TableRow { - raw: "`max_seeding_time_enabled` | bool | True enables max seeding time ", - columns: [ - "max_seeding_time_enabled", - "bool", - "True enables max seeding time", - ], - }, - TableRow { - raw: "`max_seeding_time` | integer | Number of minutes to seed a torrent", - columns: [ - "max_seeding_time", - "integer", - "Number of minutes to seed a torrent", - ], - }, - TableRow { - raw: "`announce_ip` | string | TODO", - columns: [ - "announce_ip", - "string", - "TODO", - ], - }, - TableRow { - raw: "`announce_to_all_tiers` | bool | True always announce to all tiers", - columns: [ - "announce_to_all_tiers", - "bool", - "True always announce to all tiers", - ], - }, - TableRow { - raw: "`announce_to_all_trackers` | bool | True always announce to all trackers in a tier", - columns: [ - "announce_to_all_trackers", - "bool", - "True always announce to all trackers in a tier", - ], - }, - TableRow { - raw: "`async_io_threads` | integer | Number of asynchronous I/O threads", - columns: [ - "async_io_threads", - "integer", - "Number of asynchronous I/O threads", - ], - }, - TableRow { - raw: "`banned_IPs` | string | List of banned IPs", - columns: [ - "banned_IPs", - "string", - "List of banned IPs", - ], - }, - TableRow { - raw: "`checking_memory_use` | integer | Outstanding memory when checking torrents in MiB", - columns: [ - "checking_memory_use", - "integer", - "Outstanding memory when checking torrents in MiB", - ], - }, - TableRow { - raw: "`current_interface_address` | string | IP Address to bind to. Empty String means All addresses", - columns: [ - "current_interface_address", - "string", - "IP Address to bind to. Empty String means All addresses", - ], - }, - TableRow { - raw: "`current_network_interface` | string | Network Interface used", - columns: [ - "current_network_interface", - "string", - "Network Interface used", - ], - }, - TableRow { - raw: "`disk_cache` | integer | Disk cache used in MiB", - columns: [ - "disk_cache", - "integer", - "Disk cache used in MiB", - ], - }, - TableRow { - raw: "`disk_cache_ttl` | integer | Disk cache expiry interval in seconds", - columns: [ - "disk_cache_ttl", - "integer", - "Disk cache expiry interval in seconds", - ], - }, - TableRow { - raw: "`embedded_tracker_port` | integer | Port used for embedded tracker", - columns: [ - "embedded_tracker_port", - "integer", - "Port used for embedded tracker", - ], - }, - TableRow { - raw: "`enable_coalesce_read_write` | bool | True enables coalesce reads & writes", - columns: [ - "enable_coalesce_read_write", - "bool", - "True enables coalesce reads & writes", - ], - }, - TableRow { - raw: "`enable_embedded_tracker` | bool | True enables embedded tracker", - columns: [ - "enable_embedded_tracker", - "bool", - "True enables embedded tracker", - ], - }, - TableRow { - raw: "`enable_multi_connections_from_same_ip` | bool | True allows multiple connections from the same IP address", - columns: [ - "enable_multi_connections_from_same_ip", - "bool", - "True allows multiple connections from the same IP address", - ], - }, - TableRow { - raw: "`enable_os_cache` | bool | True enables os cache", - columns: [ - "enable_os_cache", - "bool", - "True enables os cache", - ], - }, - TableRow { - raw: "`enable_upload_suggestions` | bool | True enables sending of upload piece suggestions", - columns: [ - "enable_upload_suggestions", - "bool", - "True enables sending of upload piece suggestions", - ], - }, - TableRow { - raw: "`file_pool_size` | integer | File pool size", - columns: [ - "file_pool_size", - "integer", - "File pool size", - ], - }, - TableRow { - raw: "`outgoing_ports_max` | integer | Maximal outgoing port (0: Disabled)", - columns: [ - "outgoing_ports_max", - "integer", - "Maximal outgoing port (0: Disabled)", - ], - }, - TableRow { - raw: "`outgoing_ports_min` | integer | Minimal outgoing port (0: Disabled)", - columns: [ - "outgoing_ports_min", - "integer", - "Minimal outgoing port (0: Disabled)", - ], - }, - TableRow { - raw: "`recheck_completed_torrents` | bool | True rechecks torrents on completion", - columns: [ - "recheck_completed_torrents", - "bool", - "True rechecks torrents on completion", - ], - }, - TableRow { - raw: "`resolve_peer_countries` | bool | True resolves peer countries", - columns: [ - "resolve_peer_countries", - "bool", - "True resolves peer countries", - ], - }, - TableRow { - raw: "`save_resume_data_interval` | integer | Save resume data interval in min", - columns: [ - "save_resume_data_interval", - "integer", - "Save resume data interval in min", - ], - }, - TableRow { - raw: "`send_buffer_low_watermark` | integer | Send buffer low watermark in KiB", - columns: [ - "send_buffer_low_watermark", - "integer", - "Send buffer low watermark in KiB", - ], - }, - TableRow { - raw: "`send_buffer_watermark` | integer | Send buffer watermark in KiB", - columns: [ - "send_buffer_watermark", - "integer", - "Send buffer watermark in KiB", - ], - }, - TableRow { - raw: "`send_buffer_watermark_factor` | integer | Send buffer watermark factor in percent", - columns: [ - "send_buffer_watermark_factor", - "integer", - "Send buffer watermark factor in percent", - ], - }, - TableRow { - raw: "`socket_backlog_size` | integer | Socket backlog size", - columns: [ - "socket_backlog_size", - "integer", - "Socket backlog size", - ], - }, - TableRow { - raw: "`upload_choking_algorithm` | integer | Upload choking algorithm used (see list of possible values below)", - columns: [ - "upload_choking_algorithm", - "integer", - "Upload choking algorithm used (see list of possible values below)", - ], - }, - TableRow { - raw: "`upload_slots_behavior` | integer | Upload slots behavior used (see list of possible values below)", - columns: [ - "upload_slots_behavior", - "integer", - "Upload slots behavior used (see list of possible values below)", - ], - }, - TableRow { - raw: "`upnp_lease_duration` | integer | UPnP lease duration (0: Permanent lease)", - columns: [ - "upnp_lease_duration", - "integer", - "UPnP lease duration (0: Permanent lease)", - ], - }, - TableRow { - raw: "`utp_tcp_mixed_mode` | integer | μTP-TCP mixed mode algorithm (see list of possible values below)", - columns: [ - "utp_tcp_mixed_mode", - "integer", - "μTP-TCP mixed mode algorithm (see list of possible values below)", - ], - }, - ], - }, - ), - Text( - "Possible values of `scan_dirs`:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Value | Description", - columns: [ - "Value", - "Description", - ], - }, - split: "----------------------------|------------", - rows: [ - TableRow { - raw: "`0` | Download to the monitored folder", - columns: [ - "0", - "Download to the monitored folder", - ], - }, - TableRow { - raw: "`1` | Download to the default save path", - columns: [ - "1", - "Download to the default save path", - ], - }, - TableRow { - raw: "`\"/path/to/download/to\"` | Download to this path", - columns: [ - "\"/path/to/download/to\"", - "Download to this path", - ], - }, - ], - }, - ), - Text( - "Possible values of `scheduler_days`:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Value | Description", - columns: [ - "Value", - "Description", - ], - }, - split: "-------|------------", - rows: [ - TableRow { - raw: "`0` | Every day", - columns: [ - "0", - "Every day", - ], - }, - TableRow { - raw: "`1` | Every weekday", - columns: [ - "1", - "Every weekday", - ], - }, - TableRow { - raw: "`2` | Every weekend", - columns: [ - "2", - "Every weekend", - ], - }, - TableRow { - raw: "`3` | Every Monday", - columns: [ - "3", - "Every Monday", - ], - }, - TableRow { - raw: "`4` | Every Tuesday", - columns: [ - "4", - "Every Tuesday", - ], - }, - TableRow { - raw: "`5` | Every Wednesday", - columns: [ - "5", - "Every Wednesday", - ], - }, - TableRow { - raw: "`6` | Every Thursday", - columns: [ - "6", - "Every Thursday", - ], - }, - TableRow { - raw: "`7` | Every Friday", - columns: [ - "7", - "Every Friday", - ], - }, - TableRow { - raw: "`8` | Every Saturday", - columns: [ - "8", - "Every Saturday", - ], - }, - TableRow { - raw: "`9` | Every Sunday", - columns: [ - "9", - "Every Sunday", - ], - }, - ], - }, - ), - Text( - "Possible values of `encryption`:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Value | Description", - columns: [ - "Value", - "Description", - ], - }, - split: "-------|------------", - rows: [ - TableRow { - raw: "`0` | Prefer encryption", - columns: [ - "0", - "Prefer encryption", - ], - }, - TableRow { - raw: "`1` | Force encryption on", - columns: [ - "1", - "Force encryption on", - ], - }, - TableRow { - raw: "`2` | Force encryption off", - columns: [ - "2", - "Force encryption off", - ], - }, - ], - }, - ), - Text( - "NB: the first options allows you to use both encrypted and unencrypted connections (this is the default); other options are mutually exclusive: e.g. by forcing encryption on you won't be able to use unencrypted connections and vice versa.", - ), - Text( - "", - ), - Text( - "Possible values of `proxy_type`:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Value | Description", - columns: [ - "Value", - "Description", - ], - }, - split: "------|------------", - rows: [ - TableRow { - raw: "`-1` | Proxy is disabled", - columns: [ - "-1", - "Proxy is disabled", - ], - }, - TableRow { - raw: "`1` | HTTP proxy without authentication", - columns: [ - "1", - "HTTP proxy without authentication", - ], - }, - TableRow { - raw: "`2` | SOCKS5 proxy without authentication", - columns: [ - "2", - "SOCKS5 proxy without authentication", - ], - }, - TableRow { - raw: "`3` | HTTP proxy with authentication", - columns: [ - "3", - "HTTP proxy with authentication", - ], - }, - TableRow { - raw: "`4` | SOCKS5 proxy with authentication", - columns: [ - "4", - "SOCKS5 proxy with authentication", - ], - }, - TableRow { - raw: "`5` | SOCKS4 proxy without authentication", - columns: [ - "5", - "SOCKS4 proxy without authentication", - ], - }, - ], - }, - ), - Text( - "Possible values of `dyndns_service`:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Value | Description", - columns: [ - "Value", - "Description", - ], - }, - split: "-------|------------", - rows: [ - TableRow { - raw: "`0` | Use DyDNS", - columns: [ - "0", - "Use DyDNS", - ], - }, - TableRow { - raw: "`1` | Use NOIP", - columns: [ - "1", - "Use NOIP", - ], - }, - ], - }, - ), - Text( - "Possible values of `max_ratio_act`:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Value | Description", - columns: [ - "Value", - "Description", - ], - }, - split: "------|------------", - rows: [ - TableRow { - raw: "`0` | Pause torrent", - columns: [ - "0", - "Pause torrent", - ], - }, - TableRow { - raw: "`1` | Remove torrent", - columns: [ - "1", - "Remove torrent", - ], - }, - ], - }, - ), - Text( - "Possible values of `bittorrent_protocol`:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Value | Description", - columns: [ - "Value", - "Description", - ], - }, - split: "-------|------------", - rows: [ - TableRow { - raw: "`0` | TCP and μTP", - columns: [ - "0", - "TCP and μTP", - ], - }, - TableRow { - raw: "`1` | TCP", - columns: [ - "1", - "TCP", - ], - }, - TableRow { - raw: "`2` | μTP", - columns: [ - "2", - "μTP", - ], - }, - ], - }, - ), - Text( - "Possible values of `upload_choking_algorithm`:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Value | Description", - columns: [ - "Value", - "Description", - ], - }, - split: "-------|------------", - rows: [ - TableRow { - raw: "`0` | Round-robin", - columns: [ - "0", - "Round-robin", - ], - }, - TableRow { - raw: "`1` | Fastest upload", - columns: [ - "1", - "Fastest upload", - ], - }, - TableRow { - raw: "`2` | Anti-leech", - columns: [ - "2", - "Anti-leech", - ], - }, - ], - }, - ), - Text( - "Possible values of `upload_slots_behavior`:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Value | Description", - columns: [ - "Value", - "Description", - ], - }, - split: "-------|------------", - rows: [ - TableRow { - raw: "`0` | Fixed slots", - columns: [ - "0", - "Fixed slots", - ], - }, - TableRow { - raw: "`1` | Upload rate based", - columns: [ - "1", - "Upload rate based", - ], - }, - ], - }, - ), - Text( - "Possible values of `utp_tcp_mixed_mode`:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Value | Description", - columns: [ - "Value", - "Description", - ], - }, - split: "-------|------------", - rows: [ - TableRow { - raw: "`0` | Prefer TCP", - columns: [ - "0", - "Prefer TCP", - ], - }, - TableRow { - raw: "`1` | Peer proportional", - columns: [ - "1", - "Peer proportional", - ], - }, - ], - }, - ), - Text( - "Example:", - ), - Text( - "", - ), - Text( - "```JSON", - ), - Text( - "{", - ), - Text( - " \"add_trackers\": \"\",", - ), - Text( - " \"add_trackers_enabled\": false,", - ), - Text( - " \"alt_dl_limit\": 10240,", - ), - Text( - " \"alt_up_limit\": 10240,", - ), - Text( - " \"alternative_webui_enabled\": false,", - ), - Text( - " \"alternative_webui_path\": \"/home/user/Documents/qbit-webui\",", - ), - Text( - " \"announce_ip\": \"\",", - ), - Text( - " \"announce_to_all_tiers\": true,", - ), - Text( - " \"announce_to_all_trackers\": false,", - ), - Text( - " \"anonymous_mode\": false,", - ), - Text( - " \"async_io_threads\": 4,", - ), - Text( - " \"auto_delete_mode\": 0,", - ), - Text( - " \"auto_tmm_enabled\": false,", - ), - Text( - " \"autorun_enabled\": false,", - ), - Text( - " \"autorun_program\": \"\",", - ), - Text( - " \"banned_IPs\": \"\",", - ), - Text( - " \"bittorrent_protocol\": 0,", - ), - Text( - " \"bypass_auth_subnet_whitelist\": \"\",", - ), - Text( - " \"bypass_auth_subnet_whitelist_enabled\": false,", - ), - Text( - " \"bypass_local_auth\": false,", - ), - Text( - " \"category_changed_tmm_enabled\": false,", - ), - Text( - " \"checking_memory_use\": 32,", - ), - Text( - " \"create_subfolder_enabled\": true,", - ), - Text( - " \"current_interface_address\": \"\",", - ), - Text( - " \"current_network_interface\": \"\",", - ), - Text( - " \"dht\": true,", - ), - Text( - " \"disk_cache\": -1,", - ), - Text( - " \"disk_cache_ttl\": 60,", - ), - Text( - " \"dl_limit\": 0,", - ), - Text( - " \"dont_count_slow_torrents\": false,", - ), - Text( - " \"dyndns_domain\": \"changeme.dyndns.org\",", - ), - Text( - " \"dyndns_enabled\": false,", - ), - Text( - " \"dyndns_password\": \"\",", - ), - Text( - " \"dyndns_service\": 0,", - ), - Text( - " \"dyndns_username\": \"\",", - ), - Text( - " \"embedded_tracker_port\": 9000,", - ), - Text( - " \"enable_coalesce_read_write\": false,", - ), - Text( - " \"enable_embedded_tracker\": false,", - ), - Text( - " \"enable_multi_connections_from_same_ip\": false,", - ), - Text( - " \"enable_os_cache\": true,", - ), - Text( - " \"enable_piece_extent_affinity\": false,", - ), - Text( - " \"enable_upload_suggestions\": false,", - ), - Text( - " \"encryption\": 0,", - ), - Text( - " \"export_dir\": \"/home/user/Downloads/all\",", - ), - Text( - " \"export_dir_fin\": \"/home/user/Downloads/completed\",", - ), - Text( - " \"file_pool_size\": 40,", - ), - Text( - " \"incomplete_files_ext\": false,", - ), - Text( - " \"ip_filter_enabled\": false,", - ), - Text( - " \"ip_filter_path\": \"\",", - ), - Text( - " \"ip_filter_trackers\": false,", - ), - Text( - " \"limit_lan_peers\": true,", - ), - Text( - " \"limit_tcp_overhead\": false,", - ), - Text( - " \"limit_utp_rate\": true,", - ), - Text( - " \"listen_port\": 58925,", - ), - Text( - " \"locale\": \"en\",", - ), - Text( - " \"lsd\": true,", - ), - Text( - " \"mail_notification_auth_enabled\": false,", - ), - Text( - " \"mail_notification_email\": \"\",", - ), - Text( - " \"mail_notification_enabled\": false,", - ), - Text( - " \"mail_notification_password\": \"\",", - ), - Text( - " \"mail_notification_sender\": \"qBittorrent_notification@example.com\",", - ), - Text( - " \"mail_notification_smtp\": \"smtp.changeme.com\",", - ), - Text( - " \"mail_notification_ssl_enabled\": false,", - ), - Text( - " \"mail_notification_username\": \"\",", - ), - Text( - " \"max_active_downloads\": 3,", - ), - Text( - " \"max_active_torrents\": 5,", - ), - Text( - " \"max_active_uploads\": 3,", - ), - Text( - " \"max_connec\": 500,", - ), - Text( - " \"max_connec_per_torrent\": 100,", - ), - Text( - " \"max_ratio\": -1,", - ), - Text( - " \"max_ratio_act\": 0,", - ), - Text( - " \"max_ratio_enabled\": false,", - ), - Text( - " \"max_seeding_time\": -1,", - ), - Text( - " \"max_seeding_time_enabled\": false,", - ), - Text( - " \"max_uploads\": -1,", - ), - Text( - " \"max_uploads_per_torrent\": -1,", - ), - Text( - " \"outgoing_ports_max\": 0,", - ), - Text( - " \"outgoing_ports_min\": 0,", - ), - Text( - " \"pex\": true,", - ), - Text( - " \"preallocate_all\": false,", - ), - Text( - " \"proxy_auth_enabled\": false,", - ), - Text( - " \"proxy_ip\": \"0.0.0.0\",", - ), - Text( - " \"proxy_password\": \"\",", - ), - Text( - " \"proxy_peer_connections\": false,", - ), - Text( - " \"proxy_port\": 8080,", - ), - Text( - " \"proxy_torrents_only\": false,", - ), - Text( - " \"proxy_type\": 0,", - ), - Text( - " \"proxy_username\": \"\",", - ), - Text( - " \"queueing_enabled\": false,", - ), - Text( - " \"random_port\": false,", - ), - Text( - " \"recheck_completed_torrents\": false,", - ), - Text( - " \"resolve_peer_countries\": true,", - ), - Text( - " \"rss_auto_downloading_enabled\":true,", - ), - Text( - " \"rss_download_repack_proper_episodes\":true,", - ), - Text( - " \"rss_max_articles_per_feed\":50,", - ), - Text( - " \"rss_processing_enabled\":true,", - ), - Text( - " \"rss_refresh_interval\":30,", - ), - Text( - " \"rss_smart_episode_filters\":\"s(\\\\d+)e(\\\\d+)\\n(\\\\d+)x(\\\\d+)\\n(\\\\d{4}[.\\\\-]\\\\d{1,2}[.\\\\-]\\\\d{1,2})\",", - ), - Text( - " \"save_path\": \"/home/user/Downloads/\",", - ), - Text( - " \"save_path_changed_tmm_enabled\": false,", - ), - Text( - " \"save_resume_data_interval\": 60,", - ), - Text( - " \"scan_dirs\":", - ), - Text( - " {", - ), - Text( - " \"/home/user/Downloads/incoming/games\": 0,", - ), - Text( - " \"/home/user/Downloads/incoming/movies\": 1,", - ), - Text( - " },", - ), - Text( - " \"schedule_from_hour\": 8,", - ), - Text( - " \"schedule_from_min\": 0,", - ), - Text( - " \"schedule_to_hour\": 20,", - ), - Text( - " \"schedule_to_min\": 0,", - ), - Text( - " \"scheduler_days\": 0,", - ), - Text( - " \"scheduler_enabled\": false,", - ), - Text( - " \"send_buffer_low_watermark\": 10,", - ), - Text( - " \"send_buffer_watermark\": 500,", - ), - Text( - " \"send_buffer_watermark_factor\": 50,", - ), - Text( - " \"slow_torrent_dl_rate_threshold\": 2,", - ), - Text( - " \"slow_torrent_inactive_timer\": 60,", - ), - Text( - " \"slow_torrent_ul_rate_threshold\": 2,", - ), - Text( - " \"socket_backlog_size\": 30,", - ), - Text( - " \"start_paused_enabled\": false,", - ), - Text( - " \"stop_tracker_timeout\": 1,", - ), - Text( - " \"temp_path\": \"/home/user/Downloads/temp\",", - ), - Text( - " \"temp_path_enabled\": false,", - ), - Text( - " \"torrent_changed_tmm_enabled\": true,", - ), - Text( - " \"up_limit\": 0,", - ), - Text( - " \"upload_choking_algorithm\": 1,", - ), - Text( - " \"upload_slots_behavior\": 0,", - ), - Text( - " \"upnp\": true,", - ), - Text( - " \"use_https\": false,", - ), - Text( - " \"utp_tcp_mixed_mode\": 0,", - ), - Text( - " \"web_ui_address\": \"*\",", - ), - Text( - " \"web_ui_ban_duration\": 3600,", - ), - Text( - " \"web_ui_clickjacking_protection_enabled\": true,", - ), - Text( - " \"web_ui_csrf_protection_enabled\": true,", - ), - Text( - " \"web_ui_custom_http_headers\": \"\",", - ), - Text( - " \"web_ui_domain_list\": \"*\",", - ), - Text( - " \"web_ui_host_header_validation_enabled\": true,", - ), - Text( - " \"web_ui_https_cert_path\": \"\",", - ), - Text( - " \"web_ui_https_key_path\": \"\",", - ), - Text( - " \"web_ui_max_auth_fail_count\": 5,", - ), - Text( - " \"web_ui_port\": 8080,", - ), - Text( - " \"web_ui_secure_cookie_enabled\": true,", - ), - Text( - " \"web_ui_session_timeout\": 3600,", - ), - Text( - " \"web_ui_upnp\": false,", - ), - Text( - " \"web_ui_use_custom_http_headers_enabled\": false,", - ), - Text( - " \"web_ui_username\": \"admin\"", - ), - Text( - "}", - ), - Text( - "```", - ), - Text( - "", - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Set application preferences", - ), - content: [ - Text( - "", - ), - Text( - "Name: `setPreferences`", - ), - Text( - "", - ), - Asterix( - "Parameters:", - ), - Text( - "", - ), - Text( - "A json object with key-value pairs of the settings you want to change and their new values.", - ), - Text( - "", - ), - Text( - "Example:", - ), - Text( - "", - ), - Text( - "```JSON", - ), - Text( - "json={\"save_path\":\"C:/Users/Dayman/Downloads\",\"queueing_enabled\":false,\"scan_dirs\":{\"C:/Games\": 0,\"D:/Downloads\": 1}}", - ), - Text( - "```", - ), - Text( - "", - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "200 | All scenarios", - columns: [ - "200", - "All scenarios", - ], - }, - ], - }, - ), - Asterix( - "Notes**:", - ), - Text( - "", - ), - Text( - " 1. There is no need to pass all possible preferences' `token:value` pairs if you only want to change one option", - ), - Text( - " 1. Paths in `scan_dirs` must exist, otherwise this option will have no effect", - ), - Text( - " 1. String values must be quoted; integer and boolean values must never be quoted", - ), - Text( - "", - ), - Text( - "For a list of possible preference options see [Get application preferences](#get-application-preferences)", - ), - Text( - "", - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Get default save path", - ), - content: [ - Text( - "", - ), - Text( - "Name: `defaultSavePath`", - ), - Text( - "", - ), - Asterix( - "Parameters:", - ), - Text( - "", - ), - Text( - "None", - ), - Text( - "", - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "200 | All scenarios", - columns: [ - "200", - "All scenarios", - ], - }, - ], - }, - ), - Text( - "The response is a string with the default save path, e.g. `C:/Users/Dayman/Downloads`.", - ), - Text( - "", - ), - ], - children: [], - }, - ], - }, - TokenTree { - title: Some( - "Log", - ), - content: [ - Text( - "", - ), - Text( - "All Log API methods are under \"log\", e.g.: `/api/v2/log/methodName`.", - ), - Text( - "", - ), - ], - children: [ - TokenTree { - title: Some( - "Get log", - ), - content: [ - Text( - "", - ), - Text( - "Name: `main`", - ), - Text( - "", - ), - Asterix( - "Parameters:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Parameter | Type | Description", - columns: [ - "Parameter", - "Type", - "Description", - ], - }, - split: "----------------|---------|------------", - rows: [ - TableRow { - raw: "`normal` | bool | Include normal messages (default: `true`)", - columns: [ - "normal", - "bool", - "Include normal messages (default: true)", - ], - }, - TableRow { - raw: "`info` | bool | Include info messages (default: `true`)", - columns: [ - "info", - "bool", - "Include info messages (default: true)", - ], - }, - TableRow { - raw: "`warning` | bool | Include warning messages (default: `true`)", - columns: [ - "warning", - "bool", - "Include warning messages (default: true)", - ], - }, - TableRow { - raw: "`critical` | bool | Include critical messages (default: `true`)", - columns: [ - "critical", - "bool", - "Include critical messages (default: true)", - ], - }, - TableRow { - raw: "`last_known_id` | integer | Exclude messages with \"message id\" <= `last_known_id` (default: `-1`)", - columns: [ - "last_known_id", - "integer", - "Exclude messages with \"message id\" <= last_known_id (default: -1)", - ], - }, - ], - }, - ), - Text( - "Example:", - ), - Text( - "", - ), - Text( - "```http", - ), - Text( - "/api/v2/log/main?normal=true&info=true&warning=true&critical=true&last_known_id=-1", - ), - Text( - "```", - ), - Text( - "", - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "200 | All scenarios- see JSON below", - columns: [ - "200", - "All scenarios- see JSON below", - ], - }, - ], - }, - ), - Text( - "The response is a JSON array in which each element is an entry of the log.", - ), - Text( - "", - ), - Text( - "Each element of the array has the following properties:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Property | Type | Description", - columns: [ - "Property", - "Type", - "Description", - ], - }, - split: "------------|---------|------------", - rows: [ - TableRow { - raw: "`id` | integer | ID of the message", - columns: [ - "id", - "integer", - "ID of the message", - ], - }, - TableRow { - raw: "`message` | string | Text of the message", - columns: [ - "message", - "string", - "Text of the message", - ], - }, - TableRow { - raw: "`timestamp` | integer | Milliseconds since epoch", - columns: [ - "timestamp", - "integer", - "Milliseconds since epoch", - ], - }, - TableRow { - raw: "`type` | integer | Type of the message: Log::NORMAL: `1`, Log::INFO: `2`, Log::WARNING: `4`, Log::CRITICAL: `8`", - columns: [ - "type", - "integer", - "Type of the message: Log::NORMAL: 1, Log::INFO: 2, Log::WARNING: 4, Log::CRITICAL: 8", - ], - }, - ], - }, - ), - Text( - "Example:", - ), - Text( - "", - ), - Text( - "```JSON", - ), - Text( - "[", - ), - Text( - " {", - ), - Text( - " \"id\":0,", - ), - Text( - " \"message\":\"qBittorrent v3.4.0 started\",", - ), - Text( - " \"timestamp\":1507969127860,", - ), - Text( - " \"type\":1", - ), - Text( - " },", - ), - Text( - " {", - ), - Text( - " \"id\":1,", - ), - Text( - " \"message\":\"qBittorrent is trying to listen on any interface port: 19036\",", - ), - Text( - " \"timestamp\":1507969127869,", - ), - Text( - " \"type\":2", - ), - Text( - " },", - ), - Text( - " {", - ), - Text( - " \"id\":2,", - ), - Text( - " \"message\":\"Peer ID: -qB3400-\",", - ), - Text( - " \"timestamp\":1507969127870,", - ), - Text( - " \"type\":1", - ), - Text( - " },", - ), - Text( - " {", - ), - Text( - " \"id\":3,", - ), - Text( - " \"message\":\"HTTP User-Agent is 'qBittorrent/3.4.0'\",", - ), - Text( - " \"timestamp\":1507969127870,", - ), - Text( - " \"type\":1", - ), - Text( - " },", - ), - Text( - " {", - ), - Text( - " \"id\":4,", - ), - Text( - " \"message\":\"DHT support [ON]\",", - ), - Text( - " \"timestamp\":1507969127871,", - ), - Text( - " \"type\":2", - ), - Text( - " },", - ), - Text( - " {", - ), - Text( - " \"id\":5,", - ), - Text( - " \"message\":\"Local Peer Discovery support [ON]\",", - ), - Text( - " \"timestamp\":1507969127871,", - ), - Text( - " \"type\":2", - ), - Text( - " },", - ), - Text( - " {", - ), - Text( - " \"id\":6,", - ), - Text( - " \"message\":\"PeX support [ON]\",", - ), - Text( - " \"timestamp\":1507969127871,", - ), - Text( - " \"type\":2", - ), - Text( - " },", - ), - Text( - " {", - ), - Text( - " \"id\":7,", - ), - Text( - " \"message\":\"Anonymous mode [OFF]\",", - ), - Text( - " \"timestamp\":1507969127871,", - ), - Text( - " \"type\":2", - ), - Text( - " },", - ), - Text( - " {", - ), - Text( - " \"id\":8,", - ), - Text( - " \"message\":\"Encryption support [ON]\",", - ), - Text( - " \"timestamp\":1507969127871,", - ), - Text( - " \"type\":2", - ), - Text( - " },", - ), - Text( - " {", - ), - Text( - " \"id\":9,", - ), - Text( - " \"message\":\"Embedded Tracker [OFF]\",", - ), - Text( - " \"timestamp\":1507969127871,", - ), - Text( - " \"type\":2", - ), - Text( - " },", - ), - Text( - " {", - ), - Text( - " \"id\":10,", - ), - Text( - " \"message\":\"UPnP / NAT-PMP support [ON]\",", - ), - Text( - " \"timestamp\":1507969127873,", - ), - Text( - " \"type\":2", - ), - Text( - " },", - ), - Text( - " {", - ), - Text( - " \"id\":11,", - ), - Text( - " \"message\":\"Web UI: Now listening on port 8080\",", - ), - Text( - " \"timestamp\":1507969127883,", - ), - Text( - " \"type\":1", - ), - Text( - " },", - ), - Text( - " {", - ), - Text( - " \"id\":12,", - ), - Text( - " \"message\":\"Options were saved successfully.\",", - ), - Text( - " \"timestamp\":1507969128055,", - ), - Text( - " \"type\":1", - ), - Text( - " },", - ), - Text( - " {", - ), - Text( - " \"id\":13,", - ), - Text( - " \"message\":\"qBittorrent is successfully listening on interface :: port: TCP/19036\",", - ), - Text( - " \"timestamp\":1507969128270,", - ), - Text( - " \"type\":2", - ), - Text( - " },", - ), - Text( - " {", - ), - Text( - " \"id\":14,", - ), - Text( - " \"message\":\"qBittorrent is successfully listening on interface 0.0.0.0 port: TCP/19036\",", - ), - Text( - " \"timestamp\":1507969128271,", - ), - Text( - " \"type\":2", - ), - Text( - " },", - ), - Text( - " {", - ), - Text( - " \"id\":15,", - ), - Text( - " \"message\":\"qBittorrent is successfully listening on interface 0.0.0.0 port: UDP/19036\",", - ), - Text( - " \"timestamp\":1507969128272,", - ), - Text( - " \"type\":2", - ), - Text( - " }", - ), - Text( - "]", - ), - Text( - "```", - ), - Text( - "", - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Get peer log", - ), - content: [ - Text( - "", - ), - Text( - "Name: `peers`", - ), - Text( - "", - ), - Asterix( - "Parameters:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Parameter | Type | Description", - columns: [ - "Parameter", - "Type", - "Description", - ], - }, - split: "----------------|---------|------------", - rows: [ - TableRow { - raw: "`last_known_id` | integer | Exclude messages with \"message id\" <= `last_known_id` (default: `-1`)", - columns: [ - "last_known_id", - "integer", - "Exclude messages with \"message id\" <= last_known_id (default: -1)", - ], - }, - ], - }, - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "200 | All scenarios- see JSON below", - columns: [ - "200", - "All scenarios- see JSON below", - ], - }, - ], - }, - ), - Text( - "The response a JSON array. Each element of the array of objects (each object is the information relative to a peer) containing the following fields", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Property | Type | Description", - columns: [ - "Property", - "Type", - "Description", - ], - }, - split: "------------|---------|------------", - rows: [ - TableRow { - raw: "`id` | integer | ID of the peer", - columns: [ - "id", - "integer", - "ID of the peer", - ], - }, - TableRow { - raw: "`ip` | string | IP of the peer", - columns: [ - "ip", - "string", - "IP of the peer", - ], - }, - TableRow { - raw: "`timestamp` | integer | Milliseconds since epoch", - columns: [ - "timestamp", - "integer", - "Milliseconds since epoch", - ], - }, - TableRow { - raw: "`blocked` | boolean | Whether or not the peer was blocked", - columns: [ - "blocked", - "boolean", - "Whether or not the peer was blocked", - ], - }, - TableRow { - raw: "`reason` | string | Reason of the block", - columns: [ - "reason", - "string", - "Reason of the block", - ], - }, - ], - }, - ), - ], - children: [], - }, - ], - }, - TokenTree { - title: Some( - "Sync", - ), - content: [ - Text( - "", - ), - Text( - "Sync API implements requests for obtaining changes since the last request.", - ), - Text( - "All Sync API methods are under \"sync\", e.g.: `/api/v2/sync/methodName`.", - ), - Text( - "", - ), - ], - children: [ - TokenTree { - title: Some( - "Get main data", - ), - content: [ - Text( - "", - ), - Text( - "Name: `maindata`", - ), - Text( - "", - ), - Asterix( - "Parameters:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Parameter | Type | Description", - columns: [ - "Parameter", - "Type", - "Description", - ], - }, - split: "----------|---------|------------", - rows: [ - TableRow { - raw: "`rid` | integer | Response ID. If not provided, `rid=0` will be assumed. If the given `rid` is different from the one of last server reply, `full_update` will be `true` (see the server reply details for more info)", - columns: [ - "rid", - "integer", - "Response ID. If not provided, rid=0 will be assumed. If the given rid is different from the one of last server reply, full_update will be true (see the server reply details for more info)", - ], - }, - ], - }, - ), - Text( - "Example:", - ), - Text( - "", - ), - Text( - "```http", - ), - Text( - "/api/v2/sync/maindata?rid=14", - ), - Text( - "```", - ), - Text( - "", - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "200 | All scenarios- see JSON below", - columns: [ - "200", - "All scenarios- see JSON below", - ], - }, - ], - }, - ), - Text( - "The response is a JSON object with the following possible fields", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Property | Type | Description", - columns: [ - "Property", - "Type", - "Description", - ], - }, - split: "------------------------------|---------|------------", - rows: [ - TableRow { - raw: "`rid` | integer | Response ID", - columns: [ - "rid", - "integer", - "Response ID", - ], - }, - TableRow { - raw: "`full_update` | bool | Whether the response contains all the data or partial data", - columns: [ - "full_update", - "bool", - "Whether the response contains all the data or partial data", - ], - }, - TableRow { - raw: "`torrents` | object | Property: torrent hash, value: same as [torrent list](#get-torrent-list)", - columns: [ - "torrents", - "object", - "Property: torrent hash, value: same as [torrent list](#get-torrent-list)", - ], - }, - TableRow { - raw: "`torrents_removed` | array | List of hashes of torrents removed since last request", - columns: [ - "torrents_removed", - "array", - "List of hashes of torrents removed since last request", - ], - }, - TableRow { - raw: "`categories` | object | Info for categories added since last request", - columns: [ - "categories", - "object", - "Info for categories added since last request", - ], - }, - TableRow { - raw: "`categories_removed` | array | List of categories removed since last request", - columns: [ - "categories_removed", - "array", - "List of categories removed since last request", - ], - }, - TableRow { - raw: "`tags` | array | List of tags added since last request", - columns: [ - "tags", - "array", - "List of tags added since last request", - ], - }, - TableRow { - raw: "`tags_removed` | array | List of tags removed since last request", - columns: [ - "tags_removed", - "array", - "List of tags removed since last request", - ], - }, - TableRow { - raw: "`server_state` | object | Global transfer info", - columns: [ - "server_state", - "object", - "Global transfer info", - ], - }, - ], - }, - ), - Text( - "Example:", - ), - Text( - "", - ), - Text( - "```JSON", - ), - Text( - "{", - ), - Text( - " \"rid\":15,", - ), - Text( - " \"torrents\":", - ), - Text( - " {", - ), - Text( - " \"8c212779b4abde7c6bc608063a0d008b7e40ce32\":", - ), - Text( - " {", - ), - Text( - " \"state\":\"pausedUP\"", - ), - Text( - " }", - ), - Text( - " }", - ), - Text( - "}", - ), - Text( - "```", - ), - Text( - "", - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Get torrent peers data", - ), - content: [ - Text( - "", - ), - Text( - "Name: `torrentPeers`", - ), - Text( - "", - ), - Asterix( - "Parameters:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Parameter | Type | Description", - columns: [ - "Parameter", - "Type", - "Description", - ], - }, - split: "----------|---------|------------", - rows: [ - TableRow { - raw: "`hash` | string | Torrent hash", - columns: [ - "hash", - "string", - "Torrent hash", - ], - }, - TableRow { - raw: "`rid` | integer | Response ID. If not provided, `rid=0` will be assumed. If the given `rid` is different from the one of last server reply, `full_update` will be `true` (see the server reply details for more info)", - columns: [ - "rid", - "integer", - "Response ID. If not provided, rid=0 will be assumed. If the given rid is different from the one of last server reply, full_update will be true (see the server reply details for more info)", - ], - }, - ], - }, - ), - Text( - "Example:", - ), - Text( - "", - ), - Text( - "```http", - ), - Text( - "/api/v2/sync/torrentPeers?hash=8c212779b4abde7c6bc608063a0d008b7e40ce32?rid=14", - ), - Text( - "```", - ), - Text( - "", - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "404 | Torrent hash was not found", - columns: [ - "404", - "Torrent hash was not found", - ], - }, - TableRow { - raw: "200 | All other scenarios- see JSON below", - columns: [ - "200", - "All other scenarios- see JSON below", - ], - }, - ], - }, - ), - Text( - "The response is TODO", - ), - Text( - "", - ), - ], - children: [], - }, - ], - }, - TokenTree { - title: Some( - "Transfer info", - ), - content: [ - Text( - "", - ), - Text( - "All Transfer info API methods are under \"transfer\", e.g.: `/api/v2/transfer/methodName`.", - ), - Text( - "", - ), - ], - children: [ - TokenTree { - title: Some( - "Get global transfer info", - ), - content: [ - Text( - "", - ), - Text( - "This method returns info you usually see in qBt status bar.", - ), - Text( - "", - ), - Text( - "Name: `info`", - ), - Text( - "", - ), - Asterix( - "Parameters:", - ), - Text( - "", - ), - Text( - "None", - ), - Text( - "", - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "200 | All scenarios- see JSON below", - columns: [ - "200", - "All scenarios- see JSON below", - ], - }, - ], - }, - ), - Text( - "The response is a JSON object with the following fields", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Property | Type | Description", - columns: [ - "Property", - "Type", - "Description", - ], - }, - split: "--------------------|---------|------------", - rows: [ - TableRow { - raw: "`dl_info_speed` | integer | Global download rate (bytes/s)", - columns: [ - "dl_info_speed", - "integer", - "Global download rate (bytes/s)", - ], - }, - TableRow { - raw: "`dl_info_data` | integer | Data downloaded this session (bytes)", - columns: [ - "dl_info_data", - "integer", - "Data downloaded this session (bytes)", - ], - }, - TableRow { - raw: "`up_info_speed` | integer | Global upload rate (bytes/s)", - columns: [ - "up_info_speed", - "integer", - "Global upload rate (bytes/s)", - ], - }, - TableRow { - raw: "`up_info_data` | integer | Data uploaded this session (bytes)", - columns: [ - "up_info_data", - "integer", - "Data uploaded this session (bytes)", - ], - }, - TableRow { - raw: "`dl_rate_limit` | integer | Download rate limit (bytes/s)", - columns: [ - "dl_rate_limit", - "integer", - "Download rate limit (bytes/s)", - ], - }, - TableRow { - raw: "`up_rate_limit` | integer | Upload rate limit (bytes/s)", - columns: [ - "up_rate_limit", - "integer", - "Upload rate limit (bytes/s)", - ], - }, - TableRow { - raw: "`dht_nodes` | integer | DHT nodes connected to", - columns: [ - "dht_nodes", - "integer", - "DHT nodes connected to", - ], - }, - TableRow { - raw: "`connection_status` | string | Connection status. See possible values here below", - columns: [ - "connection_status", - "string", - "Connection status. See possible values here below", - ], - }, - ], - }, - ), - Text( - "In addition to the above in partial data requests (see [Get partial data](#get-partial-data) for more info):", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Property | Type | Description", - columns: [ - "Property", - "Type", - "Description", - ], - }, - split: "-----------------------|---------|------------", - rows: [ - TableRow { - raw: "`queueing` | bool | True if torrent queueing is enabled", - columns: [ - "queueing", - "bool", - "True if torrent queueing is enabled", - ], - }, - TableRow { - raw: "`use_alt_speed_limits` | bool | True if alternative speed limits are enabled", - columns: [ - "use_alt_speed_limits", - "bool", - "True if alternative speed limits are enabled", - ], - }, - TableRow { - raw: "`refresh_interval` | integer | Transfer list refresh interval (milliseconds)", - columns: [ - "refresh_interval", - "integer", - "Transfer list refresh interval (milliseconds)", - ], - }, - ], - }, - ), - Text( - "Possible values of `connection_status`:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Value |", - columns: [ - "Value", - "", - ], - }, - split: "--------------------|", - rows: [ - TableRow { - raw: "`connected` |", - columns: [ - "connected", - "", - ], - }, - TableRow { - raw: "`firewalled` |", - columns: [ - "firewalled", - "", - ], - }, - TableRow { - raw: "`disconnected` |", - columns: [ - "disconnected", - "", - ], - }, - ], - }, - ), - Text( - "Example:", - ), - Text( - "", - ), - Text( - "```JSON", - ), - Text( - "{", - ), - Text( - " \"connection_status\":\"connected\",", - ), - Text( - " \"dht_nodes\":386,", - ), - Text( - " \"dl_info_data\":681521119,", - ), - Text( - " \"dl_info_speed\":0,", - ), - Text( - " \"dl_rate_limit\":0,", - ), - Text( - " \"up_info_data\":10747904,", - ), - Text( - " \"up_info_speed\":0,", - ), - Text( - " \"up_rate_limit\":1048576", - ), - Text( - "}", - ), - Text( - "```", - ), - Text( - "", - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Get alternative speed limits state", - ), - content: [ - Text( - "", - ), - Text( - "Name: `speedLimitsMode`", - ), - Text( - "", - ), - Asterix( - "Parameters:", - ), - Text( - "", - ), - Text( - "None", - ), - Text( - "", - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "200 | All scenarios", - columns: [ - "200", - "All scenarios", - ], - }, - ], - }, - ), - Text( - "The response is `1` if alternative speed limits are enabled, `0` otherwise.", - ), - Text( - "", - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Toggle alternative speed limits", - ), - content: [ - Text( - "", - ), - Text( - "Name: `toggleSpeedLimitsMode`", - ), - Text( - "", - ), - Asterix( - "Parameters:", - ), - Text( - "", - ), - Text( - "None", - ), - Text( - "", - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "200 | All scenarios", - columns: [ - "200", - "All scenarios", - ], - }, - ], - }, - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Get global download limit", - ), - content: [ - Text( - "", - ), - Text( - "Name: `downloadLimit`", - ), - Text( - "", - ), - Asterix( - "Parameters:", - ), - Text( - "", - ), - Text( - "None", - ), - Text( - "", - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "200 | All scenarios", - columns: [ - "200", - "All scenarios", - ], - }, - ], - }, - ), - Text( - "The response is the value of current global download speed limit in bytes/second; this value will be zero if no limit is applied.", - ), - Text( - "", - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Set global download limit", - ), - content: [ - Text( - "", - ), - Text( - "Name: `setDownloadLimit`", - ), - Text( - "", - ), - Asterix( - "Parameters:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Parameter | Type | Description", - columns: [ - "Parameter", - "Type", - "Description", - ], - }, - split: "----------------------------------|---------|------------", - rows: [ - TableRow { - raw: "`limit` | integer | The global download speed limit to set in bytes/second", - columns: [ - "limit", - "integer", - "The global download speed limit to set in bytes/second", - ], - }, - ], - }, - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "200 | All scenarios", - columns: [ - "200", - "All scenarios", - ], - }, - ], - }, - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Get global upload limit", - ), - content: [ - Text( - "", - ), - Text( - "Name: `uploadLimit`", - ), - Text( - "", - ), - Asterix( - "Parameters:", - ), - Text( - "", - ), - Text( - "None", - ), - Text( - "", - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "200 | All scenarios", - columns: [ - "200", - "All scenarios", - ], - }, - ], - }, - ), - Text( - "The response is the value of current global upload speed limit in bytes/second; this value will be zero if no limit is applied.", - ), - Text( - "", - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Set global upload limit", - ), - content: [ - Text( - "", - ), - Text( - "Name: `setUploadLimit`", - ), - Text( - "", - ), - Asterix( - "Parameters:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Parameter | Type | Description", - columns: [ - "Parameter", - "Type", - "Description", - ], - }, - split: "----------------------------------|---------|------------", - rows: [ - TableRow { - raw: "`limit` | integer | The global upload speed limit to set in bytes/second", - columns: [ - "limit", - "integer", - "The global upload speed limit to set in bytes/second", - ], - }, - ], - }, - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "200 | All scenarios", - columns: [ - "200", - "All scenarios", - ], - }, - ], - }, - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Ban peers", - ), - content: [ - Text( - "", - ), - Text( - "Name: `banPeers`", - ), - Text( - "", - ), - Asterix( - "Parameters:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Parameter | Type | Description", - columns: [ - "Parameter", - "Type", - "Description", - ], - }, - split: "----------------------------------|---------|------------", - rows: [ - TableRow { - raw: "`peers` | string | The peer to ban, or multiple peers separated by a pipe `\\|`. Each peer is a colon-separated `host:port`", - columns: [ - "peers", - "string", - "The peer to ban, or multiple peers separated by a pipe \\", - ". Each peer is a colon-separated host:port", - ], - }, - ], - }, - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "200 | All scenarios", - columns: [ - "200", - "All scenarios", - ], - }, - ], - }, - ), - ], - children: [], - }, - ], - }, - TokenTree { - title: Some( - "Torrent management", - ), - content: [ - Text( - "", - ), - Text( - "All Torrent management API methods are under \"torrents\", e.g.: `/api/v2/torrents/methodName`.", - ), - Text( - "", - ), - ], - children: [ - TokenTree { - title: Some( - "Get torrent list", - ), - content: [ - Text( - "", - ), - Text( - "Name: `info`", - ), - Text( - "", - ), - Asterix( - "Parameters:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Parameter | Type | Description", - columns: [ - "Parameter", - "Type", - "Description", - ], - }, - split: "----------------------|---------|------------", - rows: [ - TableRow { - raw: "`filter` _optional_ | string | Filter torrent list by state. Allowed state filters: `all`, `downloading`, `seeding`, `completed`, `paused`, `active`, `inactive`, `resumed`, `stalled`, `stalled_uploading`, `stalled_downloading`, `errored`", - columns: [ - "filter _optional_", - "string", - "Filter torrent list by state. Allowed state filters: all, downloading, seeding, completed, paused, active, inactive, resumed, stalled, stalled_uploading, stalled_downloading, errored", - ], - }, - TableRow { - raw: "`category` _optional_ | string | Get torrents with the given category (empty string means \"without category\"; no \"category\" parameter means \"any category\" <- broken until [#11748](https://github.com/qbittorrent/qBittorrent/issues/11748) is resolved). Remember to URL-encode the category name. For example, `My category` becomes `My%20category`", - columns: [ - "category _optional_", - "string", - "Get torrents with the given category (empty string means \"without category\"; no \"category\" parameter means \"any category\" <- broken until [#11748](https://github.com/qbittorrent/qBittorrent/issues/11748) is resolved). Remember to URL-encode the category name. For example, My category becomes My%20category", - ], - }, - TableRow { - raw: "`tag` _optional_ since 2.8.3 | string | Get torrents with the given tag (empty string means \"without tag\"; no \"tag\" parameter means \"any tag\". Remember to URL-encode the category name. For example, `My tag` becomes `My%20tag`", - columns: [ - "tag _optional_ since 2.8.3", - "string", - "Get torrents with the given tag (empty string means \"without tag\"; no \"tag\" parameter means \"any tag\". Remember to URL-encode the category name. For example, My tag becomes My%20tag", - ], - }, - TableRow { - raw: "`sort` _optional_ | string | Sort torrents by given key. They can be sorted using any field of the response's JSON array (which are documented below) as the sort key.", - columns: [ - "sort _optional_", - "string", - "Sort torrents by given key. They can be sorted using any field of the response's JSON array (which are documented below) as the sort key.", - ], - }, - TableRow { - raw: "`reverse` _optional_ | bool | Enable reverse sorting. Defaults to `false`", - columns: [ - "reverse _optional_", - "bool", - "Enable reverse sorting. Defaults to false", - ], - }, - TableRow { - raw: "`limit` _optional_ | integer | Limit the number of torrents returned", - columns: [ - "limit _optional_", - "integer", - "Limit the number of torrents returned", - ], - }, - TableRow { - raw: "`offset` _optional_ | integer | Set offset (if less than 0, offset from end)", - columns: [ - "offset _optional_", - "integer", - "Set offset (if less than 0, offset from end)", - ], - }, - TableRow { - raw: "`hashes` _optional_ | string | Filter by hashes. Can contain multiple hashes separated by `\\|`", - columns: [ - "hashes _optional_", - "string", - "Filter by hashes. Can contain multiple hashes separated by \\", - "", - ], - }, - ], - }, - ), - Text( - "Example:", - ), - Text( - "", - ), - Text( - "```http", - ), - Text( - "/api/v2/torrents/info?filter=downloading&category=sample%20category&sort=ratio", - ), - Text( - "```", - ), - Text( - "", - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "200 | All scenarios- see JSON below", - columns: [ - "200", - "All scenarios- see JSON below", - ], - }, - ], - }, - ), - Text( - "The response is a JSON array with the following fields", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Property | Type | Description", - columns: [ - "Property", - "Type", - "Description", - ], - }, - split: "---------------------|---------|------------", - rows: [ - TableRow { - raw: "`added_on` | integer | Time (Unix Epoch) when the torrent was added to the client", - columns: [ - "added_on", - "integer", - "Time (Unix Epoch) when the torrent was added to the client", - ], - }, - TableRow { - raw: "`amount_left` | integer | Amount of data left to download (bytes)", - columns: [ - "amount_left", - "integer", - "Amount of data left to download (bytes)", - ], - }, - TableRow { - raw: "`auto_tmm` | bool | Whether this torrent is managed by Automatic Torrent Management", - columns: [ - "auto_tmm", - "bool", - "Whether this torrent is managed by Automatic Torrent Management", - ], - }, - TableRow { - raw: "`availability` | float | Percentage of file pieces currently available", - columns: [ - "availability", - "float", - "Percentage of file pieces currently available", - ], - }, - TableRow { - raw: "`category` | string | Category of the torrent", - columns: [ - "category", - "string", - "Category of the torrent", - ], - }, - TableRow { - raw: "`completed` | integer | Amount of transfer data completed (bytes)", - columns: [ - "completed", - "integer", - "Amount of transfer data completed (bytes)", - ], - }, - TableRow { - raw: "`completion_on` | integer | Time (Unix Epoch) when the torrent completed", - columns: [ - "completion_on", - "integer", - "Time (Unix Epoch) when the torrent completed", - ], - }, - TableRow { - raw: "`content_path` | string | Absolute path of torrent content (root path for multifile torrents, absolute file path for singlefile torrents)", - columns: [ - "content_path", - "string", - "Absolute path of torrent content (root path for multifile torrents, absolute file path for singlefile torrents)", - ], - }, - TableRow { - raw: "`dl_limit` | integer | Torrent download speed limit (bytes/s). `-1` if ulimited.", - columns: [ - "dl_limit", - "integer", - "Torrent download speed limit (bytes/s). -1 if ulimited.", - ], - }, - TableRow { - raw: "`dlspeed` | integer | Torrent download speed (bytes/s)", - columns: [ - "dlspeed", - "integer", - "Torrent download speed (bytes/s)", - ], - }, - TableRow { - raw: "`downloaded` | integer | Amount of data downloaded", - columns: [ - "downloaded", - "integer", - "Amount of data downloaded", - ], - }, - TableRow { - raw: "`downloaded_session` | integer | Amount of data downloaded this session", - columns: [ - "downloaded_session", - "integer", - "Amount of data downloaded this session", - ], - }, - TableRow { - raw: "`eta` | integer | Torrent ETA (seconds)", - columns: [ - "eta", - "integer", - "Torrent ETA (seconds)", - ], - }, - TableRow { - raw: "`f_l_piece_prio` | bool | True if first last piece are prioritized", - columns: [ - "f_l_piece_prio", - "bool", - "True if first last piece are prioritized", - ], - }, - TableRow { - raw: "`force_start` | bool | True if force start is enabled for this torrent", - columns: [ - "force_start", - "bool", - "True if force start is enabled for this torrent", - ], - }, - TableRow { - raw: "`hash` | string | Torrent hash", - columns: [ - "hash", - "string", - "Torrent hash", - ], - }, - TableRow { - raw: "`last_activity` | integer | Last time (Unix Epoch) when a chunk was downloaded/uploaded", - columns: [ - "last_activity", - "integer", - "Last time (Unix Epoch) when a chunk was downloaded/uploaded", - ], - }, - TableRow { - raw: "`magnet_uri` | string | Magnet URI corresponding to this torrent", - columns: [ - "magnet_uri", - "string", - "Magnet URI corresponding to this torrent", - ], - }, - TableRow { - raw: "`max_ratio` | float | Maximum share ratio until torrent is stopped from seeding/uploading", - columns: [ - "max_ratio", - "float", - "Maximum share ratio until torrent is stopped from seeding/uploading", - ], - }, - TableRow { - raw: "`max_seeding_time` | integer | Maximum seeding time (seconds) until torrent is stopped from seeding", - columns: [ - "max_seeding_time", - "integer", - "Maximum seeding time (seconds) until torrent is stopped from seeding", - ], - }, - TableRow { - raw: "`name` | string | Torrent name", - columns: [ - "name", - "string", - "Torrent name", - ], - }, - TableRow { - raw: "`num_complete` | integer | Number of seeds in the swarm", - columns: [ - "num_complete", - "integer", - "Number of seeds in the swarm", - ], - }, - TableRow { - raw: "`num_incomplete` | integer | Number of leechers in the swarm", - columns: [ - "num_incomplete", - "integer", - "Number of leechers in the swarm", - ], - }, - TableRow { - raw: "`num_leechs` | integer | Number of leechers connected to", - columns: [ - "num_leechs", - "integer", - "Number of leechers connected to", - ], - }, - TableRow { - raw: "`num_seeds` | integer | Number of seeds connected to", - columns: [ - "num_seeds", - "integer", - "Number of seeds connected to", - ], - }, - TableRow { - raw: "`priority` | integer | Torrent priority. Returns -1 if queuing is disabled or torrent is in seed mode", - columns: [ - "priority", - "integer", - "Torrent priority. Returns -1 if queuing is disabled or torrent is in seed mode", - ], - }, - TableRow { - raw: "`progress` | float | Torrent progress (percentage/100)", - columns: [ - "progress", - "float", - "Torrent progress (percentage/100)", - ], - }, - TableRow { - raw: "`ratio` | float | Torrent share ratio. Max ratio value: 9999.", - columns: [ - "ratio", - "float", - "Torrent share ratio. Max ratio value: 9999.", - ], - }, - TableRow { - raw: "`ratio_limit` | float | TODO (what is different from `max_ratio`?)", - columns: [ - "ratio_limit", - "float", - "TODO (what is different from max_ratio?)", - ], - }, - TableRow { - raw: "`save_path` | string | Path where this torrent's data is stored", - columns: [ - "save_path", - "string", - "Path where this torrent's data is stored", - ], - }, - TableRow { - raw: "`seeding_time` | integer | Torrent elapsed time while complete (seconds)", - columns: [ - "seeding_time", - "integer", - "Torrent elapsed time while complete (seconds)", - ], - }, - TableRow { - raw: "`seeding_time_limit` | integer | TODO (what is different from `max_seeding_time`?) seeding_time_limit is a per torrent setting, when Automatic Torrent Management is disabled, furthermore then max_seeding_time is set to seeding_time_limit for this torrent. If Automatic Torrent Management is enabled, the value is -2. And if max_seeding_time is unset it have a default value -1.", - columns: [ - "seeding_time_limit", - "integer", - "TODO (what is different from max_seeding_time?) seeding_time_limit is a per torrent setting, when Automatic Torrent Management is disabled, furthermore then max_seeding_time is set to seeding_time_limit for this torrent. If Automatic Torrent Management is enabled, the value is -2. And if max_seeding_time is unset it have a default value -1.", - ], - }, - TableRow { - raw: "`seen_complete` | integer | Time (Unix Epoch) when this torrent was last seen complete", - columns: [ - "seen_complete", - "integer", - "Time (Unix Epoch) when this torrent was last seen complete", - ], - }, - TableRow { - raw: "`seq_dl` | bool | True if sequential download is enabled", - columns: [ - "seq_dl", - "bool", - "True if sequential download is enabled", - ], - }, - TableRow { - raw: "`size` | integer | Total size (bytes) of files selected for download", - columns: [ - "size", - "integer", - "Total size (bytes) of files selected for download", - ], - }, - TableRow { - raw: "`state` | string | Torrent state. See table here below for the possible values", - columns: [ - "state", - "string", - "Torrent state. See table here below for the possible values", - ], - }, - TableRow { - raw: "`super_seeding` | bool | True if super seeding is enabled", - columns: [ - "super_seeding", - "bool", - "True if super seeding is enabled", - ], - }, - TableRow { - raw: "`tags` | string | Comma-concatenated tag list of the torrent", - columns: [ - "tags", - "string", - "Comma-concatenated tag list of the torrent", - ], - }, - TableRow { - raw: "`time_active` | integer | Total active time (seconds)", - columns: [ - "time_active", - "integer", - "Total active time (seconds)", - ], - }, - TableRow { - raw: "`total_size` | integer | Total size (bytes) of all file in this torrent (including unselected ones)", - columns: [ - "total_size", - "integer", - "Total size (bytes) of all file in this torrent (including unselected ones)", - ], - }, - TableRow { - raw: "`tracker` | string | The first tracker with working status. Returns empty string if no tracker is working.", - columns: [ - "tracker", - "string", - "The first tracker with working status. Returns empty string if no tracker is working.", - ], - }, - TableRow { - raw: "`up_limit` | integer | Torrent upload speed limit (bytes/s). `-1` if ulimited.", - columns: [ - "up_limit", - "integer", - "Torrent upload speed limit (bytes/s). -1 if ulimited.", - ], - }, - TableRow { - raw: "`uploaded` | integer | Amount of data uploaded", - columns: [ - "uploaded", - "integer", - "Amount of data uploaded", - ], - }, - TableRow { - raw: "`uploaded_session` | integer | Amount of data uploaded this session", - columns: [ - "uploaded_session", - "integer", - "Amount of data uploaded this session", - ], - }, - TableRow { - raw: "`upspeed` | integer | Torrent upload speed (bytes/s)", - columns: [ - "upspeed", - "integer", - "Torrent upload speed (bytes/s)", - ], - }, - ], - }, - ), - Text( - "Possible values of `state`:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Value | Description", - columns: [ - "Value", - "Description", - ], - }, - split: "--------------|------------", - rows: [ - TableRow { - raw: "`error` | Some error occurred, applies to paused torrents", - columns: [ - "error", - "Some error occurred, applies to paused torrents", - ], - }, - TableRow { - raw: "`missingFiles`| Torrent data files is missing", - columns: [ - "missingFiles", - "Torrent data files is missing", - ], - }, - TableRow { - raw: "`uploading` | Torrent is being seeded and data is being transferred", - columns: [ - "uploading", - "Torrent is being seeded and data is being transferred", - ], - }, - TableRow { - raw: "`pausedUP` | Torrent is paused and has finished downloading", - columns: [ - "pausedUP", - "Torrent is paused and has finished downloading", - ], - }, - TableRow { - raw: "`queuedUP` | Queuing is enabled and torrent is queued for upload", - columns: [ - "queuedUP", - "Queuing is enabled and torrent is queued for upload", - ], - }, - TableRow { - raw: "`stalledUP` | Torrent is being seeded, but no connection were made", - columns: [ - "stalledUP", - "Torrent is being seeded, but no connection were made", - ], - }, - TableRow { - raw: "`checkingUP` | Torrent has finished downloading and is being checked", - columns: [ - "checkingUP", - "Torrent has finished downloading and is being checked", - ], - }, - TableRow { - raw: "`forcedUP` | Torrent is forced to uploading and ignore queue limit", - columns: [ - "forcedUP", - "Torrent is forced to uploading and ignore queue limit", - ], - }, - TableRow { - raw: "`allocating` | Torrent is allocating disk space for download", - columns: [ - "allocating", - "Torrent is allocating disk space for download", - ], - }, - TableRow { - raw: "`downloading` | Torrent is being downloaded and data is being transferred", - columns: [ - "downloading", - "Torrent is being downloaded and data is being transferred", - ], - }, - TableRow { - raw: "`metaDL` | Torrent has just started downloading and is fetching metadata", - columns: [ - "metaDL", - "Torrent has just started downloading and is fetching metadata", - ], - }, - TableRow { - raw: "`pausedDL` | Torrent is paused and has NOT finished downloading", - columns: [ - "pausedDL", - "Torrent is paused and has NOT finished downloading", - ], - }, - TableRow { - raw: "`queuedDL` | Queuing is enabled and torrent is queued for download", - columns: [ - "queuedDL", - "Queuing is enabled and torrent is queued for download", - ], - }, - TableRow { - raw: "`stalledDL` | Torrent is being downloaded, but no connection were made", - columns: [ - "stalledDL", - "Torrent is being downloaded, but no connection were made", - ], - }, - TableRow { - raw: "`checkingDL` | Same as checkingUP, but torrent has NOT finished downloading", - columns: [ - "checkingDL", - "Same as checkingUP, but torrent has NOT finished downloading", - ], - }, - TableRow { - raw: "`forcedDL` | Torrent is forced to downloading to ignore queue limit", - columns: [ - "forcedDL", - "Torrent is forced to downloading to ignore queue limit", - ], - }, - TableRow { - raw: "`checkingResumeData`| Checking resume data on qBt startup", - columns: [ - "checkingResumeData", - "Checking resume data on qBt startup", - ], - }, - TableRow { - raw: "`moving` | Torrent is moving to another location", - columns: [ - "moving", - "Torrent is moving to another location", - ], - }, - TableRow { - raw: "`unknown` | Unknown status", - columns: [ - "unknown", - "Unknown status", - ], - }, - ], - }, - ), - Text( - "Example:", - ), - Text( - "", - ), - Text( - "```JSON", - ), - Text( - "[", - ), - Text( - " {", - ), - Text( - " \"dlspeed\":9681262,", - ), - Text( - " \"eta\":87,", - ), - Text( - " \"f_l_piece_prio\":false,", - ), - Text( - " \"force_start\":false,", - ), - Text( - " \"hash\":\"8c212779b4abde7c6bc608063a0d008b7e40ce32\",", - ), - Text( - " \"category\":\"\",", - ), - Text( - " \"tags\": \"\",", - ), - Text( - " \"name\":\"debian-8.1.0-amd64-CD-1.iso\",", - ), - Text( - " \"num_complete\":-1,", - ), - Text( - " \"num_incomplete\":-1,", - ), - Text( - " \"num_leechs\":2,", - ), - Text( - " \"num_seeds\":54,", - ), - Text( - " \"priority\":1,", - ), - Text( - " \"progress\":0.16108787059783936,", - ), - Text( - " \"ratio\":0,", - ), - Text( - " \"seq_dl\":false,", - ), - Text( - " \"size\":657457152,", - ), - Text( - " \"state\":\"downloading\",", - ), - Text( - " \"super_seeding\":false,", - ), - Text( - " \"upspeed\":0", - ), - Text( - " },", - ), - Text( - " {", - ), - Text( - " another_torrent_info", - ), - Text( - " }", - ), - Text( - "]", - ), - Text( - "```", - ), - Text( - "", - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Get torrent generic properties", - ), - content: [ - Text( - "", - ), - Text( - "Requires knowing the torrent hash. You can get it from [torrent list](#get-torrent-list).", - ), - Text( - "", - ), - Text( - "Name: `properties`", - ), - Text( - "", - ), - Asterix( - "Parameters:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Parameter | Type | Description", - columns: [ - "Parameter", - "Type", - "Description", - ], - }, - split: "----------|--------|------------", - rows: [ - TableRow { - raw: "`hash` | string | The hash of the torrent you want to get the generic properties of", - columns: [ - "hash", - "string", - "The hash of the torrent you want to get the generic properties of", - ], - }, - ], - }, - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "404 | Torrent hash was not found", - columns: [ - "404", - "Torrent hash was not found", - ], - }, - TableRow { - raw: "200 | All other scenarios- see JSON below", - columns: [ - "200", - "All other scenarios- see JSON below", - ], - }, - ], - }, - ), - Text( - "The response is:", - ), - Text( - "", - ), - Text( - "- empty, if the torrent hash is invalid", - ), - Text( - "- otherwise, a JSON object with the following fields", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Property | Type | Description", - columns: [ - "Property", - "Type", - "Description", - ], - }, - split: "--------------------------|---------|------------", - rows: [ - TableRow { - raw: "`save_path` | string | Torrent save path", - columns: [ - "save_path", - "string", - "Torrent save path", - ], - }, - TableRow { - raw: "`creation_date` | integer | Torrent creation date (Unix timestamp)", - columns: [ - "creation_date", - "integer", - "Torrent creation date (Unix timestamp)", - ], - }, - TableRow { - raw: "`piece_size` | integer | Torrent piece size (bytes)", - columns: [ - "piece_size", - "integer", - "Torrent piece size (bytes)", - ], - }, - TableRow { - raw: "`comment` | string | Torrent comment", - columns: [ - "comment", - "string", - "Torrent comment", - ], - }, - TableRow { - raw: "`total_wasted` | integer | Total data wasted for torrent (bytes)", - columns: [ - "total_wasted", - "integer", - "Total data wasted for torrent (bytes)", - ], - }, - TableRow { - raw: "`total_uploaded` | integer | Total data uploaded for torrent (bytes)", - columns: [ - "total_uploaded", - "integer", - "Total data uploaded for torrent (bytes)", - ], - }, - TableRow { - raw: "`total_uploaded_session` | integer | Total data uploaded this session (bytes)", - columns: [ - "total_uploaded_session", - "integer", - "Total data uploaded this session (bytes)", - ], - }, - TableRow { - raw: "`total_downloaded` | integer | Total data downloaded for torrent (bytes)", - columns: [ - "total_downloaded", - "integer", - "Total data downloaded for torrent (bytes)", - ], - }, - TableRow { - raw: "`total_downloaded_session`| integer | Total data downloaded this session (bytes)", - columns: [ - "total_downloaded_session", - "integer", - "Total data downloaded this session (bytes)", - ], - }, - TableRow { - raw: "`up_limit` | integer | Torrent upload limit (bytes/s)", - columns: [ - "up_limit", - "integer", - "Torrent upload limit (bytes/s)", - ], - }, - TableRow { - raw: "`dl_limit` | integer | Torrent download limit (bytes/s)", - columns: [ - "dl_limit", - "integer", - "Torrent download limit (bytes/s)", - ], - }, - TableRow { - raw: "`time_elapsed` | integer | Torrent elapsed time (seconds)", - columns: [ - "time_elapsed", - "integer", - "Torrent elapsed time (seconds)", - ], - }, - TableRow { - raw: "`seeding_time` | integer | Torrent elapsed time while complete (seconds)", - columns: [ - "seeding_time", - "integer", - "Torrent elapsed time while complete (seconds)", - ], - }, - TableRow { - raw: "`nb_connections` | integer | Torrent connection count", - columns: [ - "nb_connections", - "integer", - "Torrent connection count", - ], - }, - TableRow { - raw: "`nb_connections_limit` | integer | Torrent connection count limit", - columns: [ - "nb_connections_limit", - "integer", - "Torrent connection count limit", - ], - }, - TableRow { - raw: "`share_ratio` | float | Torrent share ratio", - columns: [ - "share_ratio", - "float", - "Torrent share ratio", - ], - }, - TableRow { - raw: "`addition_date` | integer | When this torrent was added (unix timestamp)", - columns: [ - "addition_date", - "integer", - "When this torrent was added (unix timestamp)", - ], - }, - TableRow { - raw: "`completion_date` | integer | Torrent completion date (unix timestamp)", - columns: [ - "completion_date", - "integer", - "Torrent completion date (unix timestamp)", - ], - }, - TableRow { - raw: "`created_by` | string | Torrent creator", - columns: [ - "created_by", - "string", - "Torrent creator", - ], - }, - TableRow { - raw: "`dl_speed_avg` | integer | Torrent average download speed (bytes/second)", - columns: [ - "dl_speed_avg", - "integer", - "Torrent average download speed (bytes/second)", - ], - }, - TableRow { - raw: "`dl_speed` | integer | Torrent download speed (bytes/second)", - columns: [ - "dl_speed", - "integer", - "Torrent download speed (bytes/second)", - ], - }, - TableRow { - raw: "`eta` | integer | Torrent ETA (seconds)", - columns: [ - "eta", - "integer", - "Torrent ETA (seconds)", - ], - }, - TableRow { - raw: "`last_seen` | integer | Last seen complete date (unix timestamp)", - columns: [ - "last_seen", - "integer", - "Last seen complete date (unix timestamp)", - ], - }, - TableRow { - raw: "`peers` | integer | Number of peers connected to", - columns: [ - "peers", - "integer", - "Number of peers connected to", - ], - }, - TableRow { - raw: "`peers_total` | integer | Number of peers in the swarm", - columns: [ - "peers_total", - "integer", - "Number of peers in the swarm", - ], - }, - TableRow { - raw: "`pieces_have` | integer | Number of pieces owned", - columns: [ - "pieces_have", - "integer", - "Number of pieces owned", - ], - }, - TableRow { - raw: "`pieces_num` | integer | Number of pieces of the torrent", - columns: [ - "pieces_num", - "integer", - "Number of pieces of the torrent", - ], - }, - TableRow { - raw: "`reannounce` | integer | Number of seconds until the next announce", - columns: [ - "reannounce", - "integer", - "Number of seconds until the next announce", - ], - }, - TableRow { - raw: "`seeds` | integer | Number of seeds connected to", - columns: [ - "seeds", - "integer", - "Number of seeds connected to", - ], - }, - TableRow { - raw: "`seeds_total` | integer | Number of seeds in the swarm", - columns: [ - "seeds_total", - "integer", - "Number of seeds in the swarm", - ], - }, - TableRow { - raw: "`total_size` | integer | Torrent total size (bytes)", - columns: [ - "total_size", - "integer", - "Torrent total size (bytes)", - ], - }, - TableRow { - raw: "`up_speed_avg` | integer | Torrent average upload speed (bytes/second)", - columns: [ - "up_speed_avg", - "integer", - "Torrent average upload speed (bytes/second)", - ], - }, - TableRow { - raw: "`up_speed` | integer | Torrent upload speed (bytes/second)", - columns: [ - "up_speed", - "integer", - "Torrent upload speed (bytes/second)", - ], - }, - ], - }, - ), - Text( - "NB: `-1` is returned if the type of the property is integer but its value is not known.", - ), - Text( - "", - ), - Text( - "Example:", - ), - Text( - "", - ), - Text( - "```JSON", - ), - Text( - "{", - ), - Text( - " \"addition_date\":1438429165,", - ), - Text( - " \"comment\":\"\\\"Debian CD from cdimage.debian.org\\\"\",", - ), - Text( - " \"completion_date\":1438429234,", - ), - Text( - " \"created_by\":\"\",", - ), - Text( - " \"creation_date\":1433605214,", - ), - Text( - " \"dl_limit\":-1,", - ), - Text( - " \"dl_speed\":0,", - ), - Text( - " \"dl_speed_avg\":9736015,", - ), - Text( - " \"eta\":8640000,", - ), - Text( - " \"last_seen\":1438430354,", - ), - Text( - " \"nb_connections\":3,", - ), - Text( - " \"nb_connections_limit\":250,", - ), - Text( - " \"peers\":1,", - ), - Text( - " \"peers_total\":89,", - ), - Text( - " \"piece_size\":524288,", - ), - Text( - " \"pieces_have\":1254,", - ), - Text( - " \"pieces_num\":1254,", - ), - Text( - " \"reannounce\":672,", - ), - Text( - " \"save_path\":\"/Downloads/debian-8.1.0-amd64-CD-1.iso\",", - ), - Text( - " \"seeding_time\":1128,", - ), - Text( - " \"seeds\":1,", - ), - Text( - " \"seeds_total\":254,", - ), - Text( - " \"share_ratio\":0.00072121022562178299,", - ), - Text( - " \"time_elapsed\":1197,", - ), - Text( - " \"total_downloaded\":681521119,", - ), - Text( - " \"total_downloaded_session\":681521119,", - ), - Text( - " \"total_size\":657457152,", - ), - Text( - " \"total_uploaded\":491520,", - ), - Text( - " \"total_uploaded_session\":491520,", - ), - Text( - " \"total_wasted\":23481724,", - ), - Text( - " \"up_limit\":-1,", - ), - Text( - " \"up_speed\":0,", - ), - Text( - " \"up_speed_avg\":410", - ), - Text( - "}", - ), - Text( - "```", - ), - Text( - "", - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Get torrent trackers", - ), - content: [ - Text( - "", - ), - Text( - "Requires knowing the torrent hash. You can get it from [torrent list](#get-torrent-list).", - ), - Text( - "", - ), - Text( - "Name: `trackers`", - ), - Text( - "", - ), - Asterix( - "Parameters:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Parameter | Type | Description", - columns: [ - "Parameter", - "Type", - "Description", - ], - }, - split: "----------|--------|------------", - rows: [ - TableRow { - raw: "`hash` | string | The hash of the torrent you want to get the trackers of", - columns: [ - "hash", - "string", - "The hash of the torrent you want to get the trackers of", - ], - }, - ], - }, - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "404 | Torrent hash was not found", - columns: [ - "404", - "Torrent hash was not found", - ], - }, - TableRow { - raw: "200 | All other scenarios- see JSON below", - columns: [ - "200", - "All other scenarios- see JSON below", - ], - }, - ], - }, - ), - Text( - "The response is a JSON array, where each element contains info about one tracker, with the following fields", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Property | Type | Description", - columns: [ - "Property", - "Type", - "Description", - ], - }, - split: "-----------------|----------|-------------", - rows: [ - TableRow { - raw: "`url` | string | Tracker url", - columns: [ - "url", - "string", - "Tracker url", - ], - }, - TableRow { - raw: "`status` | integer | Tracker status. See the table below for possible values", - columns: [ - "status", - "integer", - "Tracker status. See the table below for possible values", - ], - }, - TableRow { - raw: "`tier` | integer | Tracker priority tier. Lower tier trackers are tried before higher tiers. Tier numbers are valid when `>= 0`, `< 0` is used as placeholder when `tier` does not exist for special entries (such as DHT).", - columns: [ - "tier", - "integer", - "Tracker priority tier. Lower tier trackers are tried before higher tiers. Tier numbers are valid when >= 0, < 0 is used as placeholder when tier does not exist for special entries (such as DHT).", - ], - }, - TableRow { - raw: "`num_peers` | integer | Number of peers for current torrent, as reported by the tracker", - columns: [ - "num_peers", - "integer", - "Number of peers for current torrent, as reported by the tracker", - ], - }, - TableRow { - raw: "`num_seeds` | integer | Number of seeds for current torrent, asreported by the tracker", - columns: [ - "num_seeds", - "integer", - "Number of seeds for current torrent, asreported by the tracker", - ], - }, - TableRow { - raw: "`num_leeches` | integer | Number of leeches for current torrent, as reported by the tracker", - columns: [ - "num_leeches", - "integer", - "Number of leeches for current torrent, as reported by the tracker", - ], - }, - TableRow { - raw: "`num_downloaded` | integer | Number of completed downlods for current torrent, as reported by the tracker", - columns: [ - "num_downloaded", - "integer", - "Number of completed downlods for current torrent, as reported by the tracker", - ], - }, - TableRow { - raw: "`msg` | string | Tracker message (there is no way of knowing what this message is - it's up to tracker admins)", - columns: [ - "msg", - "string", - "Tracker message (there is no way of knowing what this message is - it's up to tracker admins)", - ], - }, - ], - }, - ), - Text( - "Possible values of `status`:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Value | Description", - columns: [ - "Value", - "Description", - ], - }, - split: "-------|------------", - rows: [ - TableRow { - raw: "0 | Tracker is disabled (used for DHT, PeX, and LSD)", - columns: [ - "0", - "Tracker is disabled (used for DHT, PeX, and LSD)", - ], - }, - TableRow { - raw: "1 | Tracker has not been contacted yet", - columns: [ - "1", - "Tracker has not been contacted yet", - ], - }, - TableRow { - raw: "2 | Tracker has been contacted and is working", - columns: [ - "2", - "Tracker has been contacted and is working", - ], - }, - TableRow { - raw: "3 | Tracker is updating", - columns: [ - "3", - "Tracker is updating", - ], - }, - TableRow { - raw: "4 | Tracker has been contacted, but it is not working (or doesn't send proper replies)", - columns: [ - "4", - "Tracker has been contacted, but it is not working (or doesn't send proper replies)", - ], - }, - ], - }, - ), - Text( - "Example:", - ), - Text( - "", - ), - Text( - "```JSON", - ), - Text( - "[", - ), - Text( - " {", - ), - Text( - " \"msg\":\"\",", - ), - Text( - " \"num_peers\":100,", - ), - Text( - " \"status\":2,", - ), - Text( - " \"url\":\"http://bttracker.debian.org:6969/announce\"", - ), - Text( - " },", - ), - Text( - " {", - ), - Text( - " another_tracker_info", - ), - Text( - " }", - ), - Text( - "]", - ), - Text( - "```", - ), - Text( - "", - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Get torrent web seeds", - ), - content: [ - Text( - "", - ), - Text( - "Requires knowing the torrent hash. You can get it from [torrent list](#get-torrent-list).", - ), - Text( - "", - ), - Text( - "Name: `webseeds`", - ), - Text( - "", - ), - Asterix( - "Parameters:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Parameter | Type | Description", - columns: [ - "Parameter", - "Type", - "Description", - ], - }, - split: "----------|--------|------------", - rows: [ - TableRow { - raw: "`hash` | string | The hash of the torrent you want to get the webseeds of", - columns: [ - "hash", - "string", - "The hash of the torrent you want to get the webseeds of", - ], - }, - ], - }, - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "404 | Torrent hash was not found", - columns: [ - "404", - "Torrent hash was not found", - ], - }, - TableRow { - raw: "200 | All other scenarios- see JSON below", - columns: [ - "200", - "All other scenarios- see JSON below", - ], - }, - ], - }, - ), - Text( - "The response is a JSON array, where each element is information about one webseed, with the following fields", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Property | Type | Description", - columns: [ - "Property", - "Type", - "Description", - ], - }, - split: "--------------|----------|------------", - rows: [ - TableRow { - raw: "`url` | string | URL of the web seed", - columns: [ - "url", - "string", - "URL of the web seed", - ], - }, - ], - }, - ), - Text( - "Example:", - ), - Text( - "", - ), - Text( - "```JSON", - ), - Text( - "[", - ), - Text( - " {", - ), - Text( - " \"url\":\"http://some_url/\"", - ), - Text( - " },", - ), - Text( - " {", - ), - Text( - " \"url\":\"http://some_other_url/\"", - ), - Text( - " }", - ), - Text( - "]", - ), - Text( - "```", - ), - Text( - "", - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Get torrent contents", - ), - content: [ - Text( - "", - ), - Text( - "Requires knowing the torrent hash. You can get it from [torrent list](#get-torrent-list).", - ), - Text( - "", - ), - Text( - "Name: `files`", - ), - Text( - "", - ), - Asterix( - "Parameters:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Parameter | Type | Description", - columns: [ - "Parameter", - "Type", - "Description", - ], - }, - split: "----------|--------|------------", - rows: [ - TableRow { - raw: "`hash` | string | The hash of the torrent you want to get the contents of", - columns: [ - "hash", - "string", - "The hash of the torrent you want to get the contents of", - ], - }, - TableRow { - raw: "`indexes` _optional_ since 2.8.2 | string | The indexes of the files you want to retrieve. `indexes` can contain multiple values separated by `\\|`.", - columns: [ - "indexes _optional_ since 2.8.2", - "string", - "The indexes of the files you want to retrieve. indexes can contain multiple values separated by \\", - ".", - ], - }, - ], - }, - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "404 | Torrent hash was not found", - columns: [ - "404", - "Torrent hash was not found", - ], - }, - TableRow { - raw: "200 | All other scenarios- see JSON below", - columns: [ - "200", - "All other scenarios- see JSON below", - ], - }, - ], - }, - ), - Text( - "The response is:", - ), - Text( - "", - ), - Text( - "- empty, if the torrent hash is invalid", - ), - Text( - "- otherwise, a JSON array, where each element contains info about one file, with the following fields", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Property | Type | Description", - columns: [ - "Property", - "Type", - "Description", - ], - }, - split: "---------------|---------------|-------------", - rows: [ - TableRow { - raw: "`index` since 2.8.2 | integer | File index", - columns: [ - "index since 2.8.2", - "integer", - "File index", - ], - }, - TableRow { - raw: "`name` | string | File name (including relative path)", - columns: [ - "name", - "string", - "File name (including relative path)", - ], - }, - TableRow { - raw: "`size` | integer | File size (bytes)", - columns: [ - "size", - "integer", - "File size (bytes)", - ], - }, - TableRow { - raw: "`progress` | float | File progress (percentage/100)", - columns: [ - "progress", - "float", - "File progress (percentage/100)", - ], - }, - TableRow { - raw: "`priority` | integer | File priority. See possible values here below", - columns: [ - "priority", - "integer", - "File priority. See possible values here below", - ], - }, - TableRow { - raw: "`is_seed` | bool | True if file is seeding/complete", - columns: [ - "is_seed", - "bool", - "True if file is seeding/complete", - ], - }, - TableRow { - raw: "`piece_range` | integer array | The first number is the starting piece index and the second number is the ending piece index (inclusive)", - columns: [ - "piece_range", - "integer array", - "The first number is the starting piece index and the second number is the ending piece index (inclusive)", - ], - }, - TableRow { - raw: "`availability` | float | Percentage of file pieces currently available (percentage/100)", - columns: [ - "availability", - "float", - "Percentage of file pieces currently available (percentage/100)", - ], - }, - ], - }, - ), - Text( - "Possible values of `priority`:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Value | Description", - columns: [ - "Value", - "Description", - ], - }, - split: "-----------|------------", - rows: [ - TableRow { - raw: "`0` | Do not download", - columns: [ - "0", - "Do not download", - ], - }, - TableRow { - raw: "`1` | Normal priority", - columns: [ - "1", - "Normal priority", - ], - }, - TableRow { - raw: "`6` | High priority", - columns: [ - "6", - "High priority", - ], - }, - TableRow { - raw: "`7` | Maximal priority", - columns: [ - "7", - "Maximal priority", - ], - }, - ], - }, - ), - Text( - "Example:", - ), - Text( - "", - ), - Text( - "```JSON", - ), - Text( - "", - ), - Text( - "[", - ), - Text( - " {", - ), - Text( - " \"index\":0,", - ), - Text( - " \"is_seed\":false,", - ), - Text( - " \"name\":\"debian-8.1.0-amd64-CD-1.iso\",", - ), - Text( - " \"piece_range\":[0,1253],", - ), - Text( - " \"priority\":1,", - ), - Text( - " \"progress\":0,", - ), - Text( - " \"size\":657457152,", - ), - Text( - " \"availability\":0.5,", - ), - Text( - " }", - ), - Text( - "]", - ), - Text( - "```", - ), - Text( - "", - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Get torrent pieces' states", - ), - content: [ - Text( - "", - ), - Text( - "Requires knowing the torrent hash. You can get it from [torrent list](#get-torrent-list).", - ), - Text( - "", - ), - Text( - "Name: `pieceStates`", - ), - Text( - "", - ), - Asterix( - "Parameters:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Parameter | Type | Description", - columns: [ - "Parameter", - "Type", - "Description", - ], - }, - split: "----------|--------|------------", - rows: [ - TableRow { - raw: "`hash` | string | The hash of the torrent you want to get the pieces' states of", - columns: [ - "hash", - "string", - "The hash of the torrent you want to get the pieces' states of", - ], - }, - ], - }, - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "404 | Torrent hash was not found", - columns: [ - "404", - "Torrent hash was not found", - ], - }, - TableRow { - raw: "200 | All other scenarios- see JSON below", - columns: [ - "200", - "All other scenarios- see JSON below", - ], - }, - ], - }, - ), - Text( - "The response is:", - ), - Text( - "", - ), - Text( - "- empty, if the torrent hash is invalid", - ), - Text( - "- otherwise, an array of states (integers) of all pieces (in order) of a specific torrent.", - ), - Text( - "", - ), - Text( - "Value meanings are defined as below:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Value | Description", - columns: [ - "Value", - "Description", - ], - }, - split: "-----------|------------", - rows: [ - TableRow { - raw: "`0` | Not downloaded yet", - columns: [ - "0", - "Not downloaded yet", - ], - }, - TableRow { - raw: "`1` | Now downloading", - columns: [ - "1", - "Now downloading", - ], - }, - TableRow { - raw: "`2` | Already downloaded", - columns: [ - "2", - "Already downloaded", - ], - }, - ], - }, - ), - Text( - "Example:", - ), - Text( - "", - ), - Text( - "```JSON", - ), - Text( - "[0,0,2,1,0,0,2,1]", - ), - Text( - "```", - ), - Text( - "", - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Get torrent pieces' hashes", - ), - content: [ - Text( - "", - ), - Text( - "Requires knowing the torrent hash. You can get it from [torrent list](#get-torrent-list).", - ), - Text( - "", - ), - Text( - "Name: `pieceHashes`", - ), - Text( - "", - ), - Asterix( - "Parameters:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Parameter | Type | Description", - columns: [ - "Parameter", - "Type", - "Description", - ], - }, - split: "----------|--------|------------", - rows: [ - TableRow { - raw: "`hash` | string | The hash of the torrent you want to get the pieces' hashes of", - columns: [ - "hash", - "string", - "The hash of the torrent you want to get the pieces' hashes of", - ], - }, - ], - }, - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "404 | Torrent hash was not found", - columns: [ - "404", - "Torrent hash was not found", - ], - }, - TableRow { - raw: "200 | All other scenarios- see JSON below", - columns: [ - "200", - "All other scenarios- see JSON below", - ], - }, - ], - }, - ), - Text( - "The response is:", - ), - Text( - "", - ), - Text( - "- empty, if the torrent hash is invalid", - ), - Text( - "- otherwise, an array of hashes (strings) of all pieces (in order) of a specific torrent.", - ), - Text( - "", - ), - Text( - "Example:", - ), - Text( - "", - ), - Text( - "```JSON", - ), - Text( - "[\"54eddd830a5b58480a6143d616a97e3a6c23c439\",\"f8a99d225aa4241db100f88407fc3bdaead583ab\",\"928fb615b9bd4dd8f9e9022552c8f8f37ef76f58\"]", - ), - Text( - "```", - ), - Text( - "", - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Pause torrents", - ), - content: [ - Text( - "", - ), - Text( - "Requires knowing the torrent hashes. You can get it from [torrent list](#get-torrent-list).", - ), - Text( - "", - ), - Text( - "Name: `pause`", - ), - Text( - "", - ), - Asterix( - "Parameters:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Parameter | Type | Description", - columns: [ - "Parameter", - "Type", - "Description", - ], - }, - split: "------------|----------|------------", - rows: [ - TableRow { - raw: "`hashes` | string | The hashes of the torrents you want to pause. `hashes` can contain multiple hashes separated by `\\|`, to pause multiple torrents, or set to `all`, to pause all torrents.", - columns: [ - "hashes", - "string", - "The hashes of the torrents you want to pause. hashes can contain multiple hashes separated by \\", - ", to pause multiple torrents, or set to all, to pause all torrents.", - ], - }, - ], - }, - ), - Text( - "Example:", - ), - Text( - "", - ), - Text( - "```http", - ), - Table( - Table { - header: TableRow { - raw: "/api/v2/torrents/pause?hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|54eddd830a5b58480a6143d616a97e3a6c23c439", - columns: [ - "/api/v2/torrents/pause?hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32", - "54eddd830a5b58480a6143d616a97e3a6c23c439", - ], - }, - split: "```", - rows: [], - }, - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "200 | All scenarios", - columns: [ - "200", - "All scenarios", - ], - }, - ], - }, - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Resume torrents", - ), - content: [ - Text( - "", - ), - Text( - "Requires knowing the torrent hashes. You can get it from [torrent list](#get-torrent-list).", - ), - Text( - "", - ), - Text( - "Name: `resume`", - ), - Text( - "", - ), - Asterix( - "Parameters:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Parameter | Type | Description", - columns: [ - "Parameter", - "Type", - "Description", - ], - }, - split: "------------|----------|------------", - rows: [ - TableRow { - raw: "`hashes` | string | The hashes of the torrents you want to resume. `hashes` can contain multiple hashes separated by `\\|`, to resume multiple torrents, or set to `all`, to resume all torrents.", - columns: [ - "hashes", - "string", - "The hashes of the torrents you want to resume. hashes can contain multiple hashes separated by \\", - ", to resume multiple torrents, or set to all, to resume all torrents.", - ], - }, - ], - }, - ), - Text( - "Example:", - ), - Text( - "", - ), - Text( - "```http", - ), - Table( - Table { - header: TableRow { - raw: "/api/v2/torrents/resume?hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|54eddd830a5b58480a6143d616a97e3a6c23c439", - columns: [ - "/api/v2/torrents/resume?hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32", - "54eddd830a5b58480a6143d616a97e3a6c23c439", - ], - }, - split: "```", - rows: [], - }, - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "200 | All scenarios", - columns: [ - "200", - "All scenarios", - ], - }, - ], - }, - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Delete torrents", - ), - content: [ - Text( - "", - ), - Text( - "Requires knowing the torrent hashes. You can get it from [torrent list](#get-torrent-list).", - ), - Text( - "", - ), - Text( - "Name: `delete`", - ), - Text( - "", - ), - Asterix( - "Parameters:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Parameter | Type | Description", - columns: [ - "Parameter", - "Type", - "Description", - ], - }, - split: "------------|----------|------------", - rows: [ - TableRow { - raw: "`hashes` | string | The hashes of the torrents you want to delete. `hashes` can contain multiple hashes separated by `\\|`, to delete multiple torrents, or set to `all`, to delete all torrents.", - columns: [ - "hashes", - "string", - "The hashes of the torrents you want to delete. hashes can contain multiple hashes separated by \\", - ", to delete multiple torrents, or set to all, to delete all torrents.", - ], - }, - TableRow { - raw: "`deleteFiles` | If set to `true`, the downloaded data will also be deleted, otherwise has no effect.", - columns: [ - "deleteFiles", - "If set to true, the downloaded data will also be deleted, otherwise has no effect.", - ], - }, - ], - }, - ), - Text( - "Example:", - ), - Text( - "", - ), - Text( - "```http", - ), - Text( - "/api/v2/torrents/delete?hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32&deleteFiles=false", - ), - Text( - "```", - ), - Text( - "", - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "200 | All scenarios", - columns: [ - "200", - "All scenarios", - ], - }, - ], - }, - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Recheck torrents", - ), - content: [ - Text( - "", - ), - Text( - "Requires knowing the torrent hashes. You can get it from [torrent list](#get-torrent-list).", - ), - Text( - "", - ), - Text( - "Name: `recheck`", - ), - Text( - "", - ), - Asterix( - "Parameters:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Parameter | Type | Description", - columns: [ - "Parameter", - "Type", - "Description", - ], - }, - split: "------------|----------|------------", - rows: [ - TableRow { - raw: "`hashes` | string | The hashes of the torrents you want to recheck. `hashes` can contain multiple hashes separated by `\\|`, to recheck multiple torrents, or set to `all`, to recheck all torrents.", - columns: [ - "hashes", - "string", - "The hashes of the torrents you want to recheck. hashes can contain multiple hashes separated by \\", - ", to recheck multiple torrents, or set to all, to recheck all torrents.", - ], - }, - ], - }, - ), - Text( - "Example:", - ), - Text( - "", - ), - Text( - "```http", - ), - Table( - Table { - header: TableRow { - raw: "/api/v2/torrents/recheck?hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|54eddd830a5b58480a6143d616a97e3a6c23c439", - columns: [ - "/api/v2/torrents/recheck?hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32", - "54eddd830a5b58480a6143d616a97e3a6c23c439", - ], - }, - split: "```", - rows: [], - }, - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "200 | All scenarios", - columns: [ - "200", - "All scenarios", - ], - }, - ], - }, - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Reannounce torrents", - ), - content: [ - Text( - "", - ), - Text( - "Requires knowing the torrent hashes. You can get it from [torrent list](#get-torrent-list).", - ), - Text( - "", - ), - Text( - "Name: `reannounce`", - ), - Text( - "", - ), - Asterix( - "Parameters:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Parameter | Type | Description", - columns: [ - "Parameter", - "Type", - "Description", - ], - }, - split: "------------|----------|------------", - rows: [ - TableRow { - raw: "`hashes` | string | The hashes of the torrents you want to reannounce. `hashes` can contain multiple hashes separated by `\\|`, to reannounce multiple torrents, or set to `all`, to reannounce all torrents.", - columns: [ - "hashes", - "string", - "The hashes of the torrents you want to reannounce. hashes can contain multiple hashes separated by \\", - ", to reannounce multiple torrents, or set to all, to reannounce all torrents.", - ], - }, - ], - }, - ), - Text( - "Example:", - ), - Text( - "", - ), - Text( - "```http", - ), - Table( - Table { - header: TableRow { - raw: "/api/v2/torrents/reannounce?hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|54eddd830a5b58480a6143d616a97e3a6c23c439", - columns: [ - "/api/v2/torrents/reannounce?hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32", - "54eddd830a5b58480a6143d616a97e3a6c23c439", - ], - }, - split: "```", - rows: [], - }, - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "200 | All scenarios", - columns: [ - "200", - "All scenarios", - ], - }, - ], - }, - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Add new torrent", - ), - content: [ - Text( - "", - ), - Text( - "This method can add torrents from server local file or from URLs. `http://`, `https://`, `magnet:` and `bc://bt/` links are supported.", - ), - Text( - "", - ), - Text( - "Name: `add`", - ), - Text( - "", - ), - Text( - "Add torrent from URLs example:", - ), - Text( - "", - ), - Text( - "```http", - ), - Text( - "POST /api/v2/torrents/add HTTP/1.1", - ), - Text( - "User-Agent: Fiddler", - ), - Text( - "Host: 127.0.0.1", - ), - Text( - "Cookie: SID=your_sid", - ), - Text( - "Content-Type: multipart/form-data; boundary=---------------------------6688794727912", - ), - Text( - "Content-Length: length", - ), - Text( - "", - ), - Text( - "-----------------------------6688794727912", - ), - Text( - "Content-Disposition: form-data; name=\"urls\"", - ), - Text( - "", - ), - Text( - "https://torcache.net/torrent/3B1A1469C180F447B77021074DBBCCAEF62611E7.torrent", - ), - Text( - "https://torcache.net/torrent/3B1A1469C180F447B77021074DBBCCAEF62611E8.torrent", - ), - Text( - "-----------------------------6688794727912", - ), - Text( - "Content-Disposition: form-data; name=\"savepath\"", - ), - Text( - "", - ), - Text( - "C:/Users/qBit/Downloads", - ), - Text( - "-----------------------------6688794727912", - ), - Text( - "Content-Disposition: form-data; name=\"cookie\"", - ), - Text( - "", - ), - Text( - "ui=28979218048197", - ), - Text( - "-----------------------------6688794727912", - ), - Text( - "Content-Disposition: form-data; name=\"category\"", - ), - Text( - "", - ), - Text( - "movies", - ), - Text( - "-----------------------------6688794727912", - ), - Text( - "Content-Disposition: form-data; name=\"skip_checking\"", - ), - Text( - "", - ), - Text( - "true", - ), - Text( - "-----------------------------6688794727912", - ), - Text( - "Content-Disposition: form-data; name=\"paused\"", - ), - Text( - "", - ), - Text( - "true", - ), - Text( - "-----------------------------6688794727912", - ), - Text( - "Content-Disposition: form-data; name=\"root_folder\"", - ), - Text( - "", - ), - Text( - "true", - ), - Text( - "-----------------------------6688794727912--", - ), - Text( - "```", - ), - Text( - "", - ), - Text( - "Add torrents from files example:", - ), - Text( - "", - ), - Text( - "```http", - ), - Text( - "POST /api/v2/torrents/add HTTP/1.1", - ), - Text( - "Content-Type: multipart/form-data; boundary=-------------------------acebdf13572468", - ), - Text( - "User-Agent: Fiddler", - ), - Text( - "Host: 127.0.0.1", - ), - Text( - "Cookie: SID=your_sid", - ), - Text( - "Content-Length: length", - ), - Text( - "", - ), - Text( - "---------------------------acebdf13572468", - ), - Text( - "Content-Disposition: form-data; name=\"torrents\"; filename=\"8f18036b7a205c9347cb84a253975e12f7adddf2.torrent\"", - ), - Text( - "Content-Type: application/x-bittorrent", - ), - Text( - "", - ), - Text( - "file_binary_data_goes_here", - ), - Text( - "---------------------------acebdf13572468", - ), - Text( - "Content-Disposition: form-data; name=\"torrents\"; filename=\"UFS.torrent\"", - ), - Text( - "Content-Type: application/x-bittorrent", - ), - Text( - "", - ), - Text( - "file_binary_data_goes_here", - ), - Text( - "---------------------------acebdf13572468--", - ), - Text( - "", - ), - Text( - "```", - ), - Text( - "", - ), - Text( - "The above example will add two torrent files. `file_binary_data_goes_here` represents raw data of torrent file (basically a byte array).", - ), - Text( - "", - ), - Asterix( - "Parameters:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Property | Type | Description", - columns: [ - "Property", - "Type", - "Description", - ], - }, - split: "--------------------------------|---------|------------", - rows: [ - TableRow { - raw: "`urls` | string | URLs separated with newlines", - columns: [ - "urls", - "string", - "URLs separated with newlines", - ], - }, - TableRow { - raw: "`torrents` | raw | Raw data of torrent file. `torrents` can be presented multiple times.", - columns: [ - "torrents", - "raw", - "Raw data of torrent file. torrents can be presented multiple times.", - ], - }, - TableRow { - raw: "`savepath` _optional_ | string | Download folder", - columns: [ - "savepath _optional_", - "string", - "Download folder", - ], - }, - TableRow { - raw: "`cookie` _optional_ | string | Cookie sent to download the .torrent file", - columns: [ - "cookie _optional_", - "string", - "Cookie sent to download the .torrent file", - ], - }, - TableRow { - raw: "`category` _optional_ | string | Category for the torrent", - columns: [ - "category _optional_", - "string", - "Category for the torrent", - ], - }, - TableRow { - raw: "`tags` _optional_ | string | Tags for the torrent, split by ','", - columns: [ - "tags _optional_", - "string", - "Tags for the torrent, split by ','", - ], - }, - TableRow { - raw: "`skip_checking` _optional_ | string | Skip hash checking. Possible values are `true`, `false` (default)", - columns: [ - "skip_checking _optional_", - "string", - "Skip hash checking. Possible values are true, false (default)", - ], - }, - TableRow { - raw: "`paused` _optional_ | string | Add torrents in the paused state. Possible values are `true`, `false` (default)", - columns: [ - "paused _optional_", - "string", - "Add torrents in the paused state. Possible values are true, false (default)", - ], - }, - TableRow { - raw: "`root_folder` _optional_ | string | Create the root folder. Possible values are `true`, `false`, unset (default)", - columns: [ - "root_folder _optional_", - "string", - "Create the root folder. Possible values are true, false, unset (default)", - ], - }, - TableRow { - raw: "`rename` _optional_ | string | Rename torrent", - columns: [ - "rename _optional_", - "string", - "Rename torrent", - ], - }, - TableRow { - raw: "`upLimit` _optional_ | integer | Set torrent upload speed limit. Unit in bytes/second", - columns: [ - "upLimit _optional_", - "integer", - "Set torrent upload speed limit. Unit in bytes/second", - ], - }, - TableRow { - raw: "`dlLimit` _optional_ | integer | Set torrent download speed limit. Unit in bytes/second", - columns: [ - "dlLimit _optional_", - "integer", - "Set torrent download speed limit. Unit in bytes/second", - ], - }, - TableRow { - raw: "`ratioLimit` _optional_ since 2.8.1 | float | Set torrent share ratio limit", - columns: [ - "ratioLimit _optional_ since 2.8.1", - "float", - "Set torrent share ratio limit", - ], - }, - TableRow { - raw: "`seedingTimeLimit` _optional_ since 2.8.1 | integer | Set torrent seeding time limit. Unit in seconds", - columns: [ - "seedingTimeLimit _optional_ since 2.8.1", - "integer", - "Set torrent seeding time limit. Unit in seconds", - ], - }, - TableRow { - raw: "`autoTMM` _optional_ | bool | Whether Automatic Torrent Management should be used", - columns: [ - "autoTMM _optional_", - "bool", - "Whether Automatic Torrent Management should be used", - ], - }, - TableRow { - raw: "`sequentialDownload` _optional_ | string | Enable sequential download. Possible values are `true`, `false` (default)", - columns: [ - "sequentialDownload _optional_", - "string", - "Enable sequential download. Possible values are true, false (default)", - ], - }, - TableRow { - raw: "`firstLastPiecePrio` _optional_ | string | Prioritize download first last piece. Possible values are `true`, `false` (default)", - columns: [ - "firstLastPiecePrio _optional_", - "string", - "Prioritize download first last piece. Possible values are true, false (default)", - ], - }, - ], - }, - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "415 | Torrent file is not valid", - columns: [ - "415", - "Torrent file is not valid", - ], - }, - TableRow { - raw: "200 | All other scenarios", - columns: [ - "200", - "All other scenarios", - ], - }, - ], - }, - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Add trackers to torrent", - ), - content: [ - Text( - "", - ), - Text( - "Requires knowing the torrent hash. You can get it from [torrent list](#get-torrent-list).", - ), - Text( - "", - ), - Text( - "Name: `addTrackers`", - ), - Text( - "", - ), - Text( - "```http", - ), - Text( - "POST /api/v2/torrents/addTrackers HTTP/1.1", - ), - Text( - "User-Agent: Fiddler", - ), - Text( - "Host: 127.0.0.1", - ), - Text( - "Cookie: SID=your_sid", - ), - Text( - "Content-Type: application/x-www-form-urlencoded", - ), - Text( - "Content-Length: length", - ), - Text( - "", - ), - Text( - "hash=8c212779b4abde7c6bc608063a0d008b7e40ce32&urls=http://192.168.0.1/announce%0Audp://192.168.0.1:3333/dummyAnnounce", - ), - Text( - "```", - ), - Text( - "", - ), - Text( - "This adds two trackers to torrent with hash `8c212779b4abde7c6bc608063a0d008b7e40ce32`. Note `%0A` (aka LF newline) between trackers. Ampersand in tracker urls **MUST** be escaped.", - ), - Text( - "", - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "404 | Torrent hash was not found", - columns: [ - "404", - "Torrent hash was not found", - ], - }, - TableRow { - raw: "200 | All other scenarios", - columns: [ - "200", - "All other scenarios", - ], - }, - ], - }, - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Edit trackers", - ), - content: [ - Text( - "", - ), - Text( - "Name: `editTracker`", - ), - Text( - "", - ), - Asterix( - "Parameters:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Parameter | Type | Description", - columns: [ - "Parameter", - "Type", - "Description", - ], - }, - split: "----------------------------------|---------|------------", - rows: [ - TableRow { - raw: "`hash` | string | The hash of the torrent", - columns: [ - "hash", - "string", - "The hash of the torrent", - ], - }, - TableRow { - raw: "`origUrl` | string | The tracker URL you want to edit", - columns: [ - "origUrl", - "string", - "The tracker URL you want to edit", - ], - }, - TableRow { - raw: "`newUrl` | string | The new URL to replace the `origUrl`", - columns: [ - "newUrl", - "string", - "The new URL to replace the origUrl", - ], - }, - ], - }, - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "400 | `newUrl` is not a valid URL", - columns: [ - "400", - "newUrl is not a valid URL", - ], - }, - TableRow { - raw: "404 | Torrent hash was not found", - columns: [ - "404", - "Torrent hash was not found", - ], - }, - TableRow { - raw: "409 | `newUrl` already exists for the torrent", - columns: [ - "409", - "newUrl already exists for the torrent", - ], - }, - TableRow { - raw: "409 | `origUrl` was not found", - columns: [ - "409", - "origUrl was not found", - ], - }, - TableRow { - raw: "200 | All other scenarios", - columns: [ - "200", - "All other scenarios", - ], - }, - ], - }, - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Remove trackers", - ), - content: [ - Text( - "", - ), - Text( - "Name: `removeTrackers`", - ), - Text( - "", - ), - Asterix( - "Parameters:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Parameter | Type | Description", - columns: [ - "Parameter", - "Type", - "Description", - ], - }, - split: "----------------------------------|---------|------------", - rows: [ - TableRow { - raw: "`hash` | string | The hash of the torrent", - columns: [ - "hash", - "string", - "The hash of the torrent", - ], - }, - TableRow { - raw: "`urls` | string | URLs to remove, separated by `\\|`", - columns: [ - "urls", - "string", - "URLs to remove, separated by \\", - "", - ], - }, - ], - }, - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "404 | Torrent hash was not found", - columns: [ - "404", - "Torrent hash was not found", - ], - }, - TableRow { - raw: "409 | All `urls` were not found", - columns: [ - "409", - "All urls were not found", - ], - }, - TableRow { - raw: "200 | All other scenarios", - columns: [ - "200", - "All other scenarios", - ], - }, - ], - }, - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Add peers", - ), - content: [ - Text( - "", - ), - Text( - "Name: `addPeers`", - ), - Text( - "", - ), - Asterix( - "Parameters:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Parameter | Type | Description", - columns: [ - "Parameter", - "Type", - "Description", - ], - }, - split: "----------------------------------|---------|------------", - rows: [ - TableRow { - raw: "`hashes` | string | The hash of the torrent, or multiple hashes separated by a pipe `\\|`", - columns: [ - "hashes", - "string", - "The hash of the torrent, or multiple hashes separated by a pipe \\", - "", - ], - }, - TableRow { - raw: "`peers` | string | The peer to add, or multiple peers separated by a pipe `\\|`. Each peer is a colon-separated `host:port`", - columns: [ - "peers", - "string", - "The peer to add, or multiple peers separated by a pipe \\", - ". Each peer is a colon-separated host:port", - ], - }, - ], - }, - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "400 | None of the supplied peers are valid", - columns: [ - "400", - "None of the supplied peers are valid", - ], - }, - TableRow { - raw: "200 | All other scenarios", - columns: [ - "200", - "All other scenarios", - ], - }, - ], - }, - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Increase torrent priority", - ), - content: [ - Text( - "", - ), - Text( - "Requires knowing the torrent hash. You can get it from [torrent list](#get-torrent-list).", - ), - Text( - "", - ), - Text( - "Name: `increasePrio`", - ), - Text( - "", - ), - Asterix( - "Parameters:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Parameter | Type | Description", - columns: [ - "Parameter", - "Type", - "Description", - ], - }, - split: "------------|----------|------------", - rows: [ - TableRow { - raw: "`hashes` | string | The hashes of the torrents you want to increase the priority of. `hashes` can contain multiple hashes separated by `\\|`, to increase the priority of multiple torrents, or set to `all`, to increase the priority of all torrents.", - columns: [ - "hashes", - "string", - "The hashes of the torrents you want to increase the priority of. hashes can contain multiple hashes separated by \\", - ", to increase the priority of multiple torrents, or set to all, to increase the priority of all torrents.", - ], - }, - ], - }, - ), - Text( - "Example:", - ), - Text( - "", - ), - Text( - "```http", - ), - Table( - Table { - header: TableRow { - raw: "/api/v2/torrents/increasePrio?hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|54eddd830a5b58480a6143d616a97e3a6c23c439", - columns: [ - "/api/v2/torrents/increasePrio?hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32", - "54eddd830a5b58480a6143d616a97e3a6c23c439", - ], - }, - split: "```", - rows: [], - }, - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "409 | Torrent queueing is not enabled", - columns: [ - "409", - "Torrent queueing is not enabled", - ], - }, - TableRow { - raw: "200 | All other scenarios", - columns: [ - "200", - "All other scenarios", - ], - }, - ], - }, - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Decrease torrent priority", - ), - content: [ - Text( - "", - ), - Text( - "Requires knowing the torrent hash. You can get it from [torrent list](#get-torrent-list).", - ), - Text( - "", - ), - Text( - "Name: `decreasePrio`", - ), - Text( - "", - ), - Asterix( - "Parameters:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Parameter | Type | Description", - columns: [ - "Parameter", - "Type", - "Description", - ], - }, - split: "------------|----------|------------", - rows: [ - TableRow { - raw: "`hashes` | string | The hashes of the torrents you want to decrease the priority of. `hashes` can contain multiple hashes separated by `\\|`, to decrease the priority of multiple torrents, or set to `all`, to decrease the priority of all torrents.", - columns: [ - "hashes", - "string", - "The hashes of the torrents you want to decrease the priority of. hashes can contain multiple hashes separated by \\", - ", to decrease the priority of multiple torrents, or set to all, to decrease the priority of all torrents.", - ], - }, - ], - }, - ), - Text( - "Example:", - ), - Text( - "", - ), - Text( - "```http", - ), - Table( - Table { - header: TableRow { - raw: "/api/v2/torrents/decreasePrio?hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|54eddd830a5b58480a6143d616a97e3a6c23c439", - columns: [ - "/api/v2/torrents/decreasePrio?hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32", - "54eddd830a5b58480a6143d616a97e3a6c23c439", - ], - }, - split: "```", - rows: [], - }, - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "409 | Torrent queueing is not enabled", - columns: [ - "409", - "Torrent queueing is not enabled", - ], - }, - TableRow { - raw: "200 | All other scenarios", - columns: [ - "200", - "All other scenarios", - ], - }, - ], - }, - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Maximal torrent priority", - ), - content: [ - Text( - "", - ), - Text( - "Requires knowing the torrent hash. You can get it from [torrent list](#get-torrent-list).", - ), - Text( - "", - ), - Text( - "Name: `topPrio`", - ), - Text( - "", - ), - Asterix( - "Parameters:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Parameter | Type | Description", - columns: [ - "Parameter", - "Type", - "Description", - ], - }, - split: "------------|----------|------------", - rows: [ - TableRow { - raw: "`hashes` | string | The hashes of the torrents you want to set to the maximum priority. `hashes` can contain multiple hashes separated by `\\|`, to set multiple torrents to the maximum priority, or set to `all`, to set all torrents to the maximum priority.", - columns: [ - "hashes", - "string", - "The hashes of the torrents you want to set to the maximum priority. hashes can contain multiple hashes separated by \\", - ", to set multiple torrents to the maximum priority, or set to all, to set all torrents to the maximum priority.", - ], - }, - ], - }, - ), - Text( - "Example:", - ), - Text( - "", - ), - Text( - "```http", - ), - Table( - Table { - header: TableRow { - raw: "/api/v2/torrents/topPrio?hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|54eddd830a5b58480a6143d616a97e3a6c23c439", - columns: [ - "/api/v2/torrents/topPrio?hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32", - "54eddd830a5b58480a6143d616a97e3a6c23c439", - ], - }, - split: "```", - rows: [], - }, - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "409 | Torrent queueing is not enabled", - columns: [ - "409", - "Torrent queueing is not enabled", - ], - }, - TableRow { - raw: "200 | All other scenarios", - columns: [ - "200", - "All other scenarios", - ], - }, - ], - }, - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Minimal torrent priority", - ), - content: [ - Text( - "", - ), - Text( - "Requires knowing the torrent hash. You can get it from [torrent list](#get-torrent-list).", - ), - Text( - "", - ), - Text( - "Name: `bottomPrio`", - ), - Text( - "", - ), - Asterix( - "Parameters:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Parameter | Type | Description", - columns: [ - "Parameter", - "Type", - "Description", - ], - }, - split: "------------|----------|------------", - rows: [ - TableRow { - raw: "`hashes` | string | The hashes of the torrents you want to set to the minimum priority. `hashes` can contain multiple hashes separated by `\\|`, to set multiple torrents to the minimum priority, or set to `all`, to set all torrents to the minimum priority.", - columns: [ - "hashes", - "string", - "The hashes of the torrents you want to set to the minimum priority. hashes can contain multiple hashes separated by \\", - ", to set multiple torrents to the minimum priority, or set to all, to set all torrents to the minimum priority.", - ], - }, - ], - }, - ), - Text( - "Example:", - ), - Text( - "", - ), - Text( - "```http", - ), - Table( - Table { - header: TableRow { - raw: "/api/v2/torrents/bottomPrio?hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|54eddd830a5b58480a6143d616a97e3a6c23c439", - columns: [ - "/api/v2/torrents/bottomPrio?hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32", - "54eddd830a5b58480a6143d616a97e3a6c23c439", - ], - }, - split: "```", - rows: [], - }, - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "409 | Torrent queueing is not enabled", - columns: [ - "409", - "Torrent queueing is not enabled", - ], - }, - TableRow { - raw: "200 | All other scenarios", - columns: [ - "200", - "All other scenarios", - ], - }, - ], - }, - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Set file priority", - ), - content: [ - Text( - "", - ), - Text( - "Name: `filePrio`", - ), - Text( - "", - ), - Asterix( - "Parameters:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Parameter | Type | Description", - columns: [ - "Parameter", - "Type", - "Description", - ], - }, - split: "----------------------------------|---------|------------", - rows: [ - TableRow { - raw: "`hash` | string | The hash of the torrent", - columns: [ - "hash", - "string", - "The hash of the torrent", - ], - }, - TableRow { - raw: "`id` | string | File ids, separated by `\\|`", - columns: [ - "id", - "string", - "File ids, separated by \\", - "", - ], - }, - TableRow { - raw: "`priority` | number | File priority to set (consult [torrent contents API](#get-torrent-contents) for possible values)", - columns: [ - "priority", - "number", - "File priority to set (consult [torrent contents API](#get-torrent-contents) for possible values)", - ], - }, - ], - }, - ), - Text( - "`id` values correspond to file position inside the array returned by [torrent contents API](#get-torrent-contents), e.g. `id=0` for first file, `id=1` for second file, etc.", - ), - Text( - "", - ), - Text( - "Since 2.8.2 it is reccomended to use `index` field returned by [torrent contents API](#get-torrent-contents) (since the files can be filtered and the `index` value may differ from the position inside the response array).", - ), - Text( - "", - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "400 | Priority is invalid", - columns: [ - "400", - "Priority is invalid", - ], - }, - TableRow { - raw: "400 | At least one file `id` is not a valid integer", - columns: [ - "400", - "At least one file id is not a valid integer", - ], - }, - TableRow { - raw: "404 | Torrent hash was not found", - columns: [ - "404", - "Torrent hash was not found", - ], - }, - TableRow { - raw: "409 | Torrent metadata hasn't downloaded yet", - columns: [ - "409", - "Torrent metadata hasn't downloaded yet", - ], - }, - TableRow { - raw: "409 | At least one file `id` was not found", - columns: [ - "409", - "At least one file id was not found", - ], - }, - TableRow { - raw: "200 | All other scenarios", - columns: [ - "200", - "All other scenarios", - ], - }, - ], - }, - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Get torrent download limit", - ), - content: [ - Text( - "", - ), - Text( - "Requires knowing the torrent hash. You can get it from [torrent list](#get-torrent-list).", - ), - Text( - "", - ), - Text( - "Name: `downloadLimit`", - ), - Text( - "", - ), - Text( - "```http", - ), - Text( - "POST /api/v2/torrents/downloadLimit HTTP/1.1", - ), - Text( - "User-Agent: Fiddler", - ), - Text( - "Host: 127.0.0.1", - ), - Text( - "Cookie: SID=your_sid", - ), - Text( - "Content-Type: application/x-www-form-urlencoded", - ), - Text( - "Content-Length: length", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|284b83c9c7935002391129fd97f43db5d7cc2ba0", - columns: [ - "hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32", - "284b83c9c7935002391129fd97f43db5d7cc2ba0", - ], - }, - split: "```", - rows: [], - }, - ), - Table( - Table { - header: TableRow { - raw: "`hashes` can contain multiple hashes separated by `|` or set to `all`", - columns: [ - "hashes can contain multiple hashes separated by", - "or set to all", - ], - }, - split: "", - rows: [], - }, - ), - Text( - "", - ), - Text( - "```http", - ), - Text( - "HTTP/1.1 200 OK", - ), - Text( - "content-type: application/json", - ), - Text( - "content-length: length", - ), - Text( - "", - ), - Text( - "{\"8c212779b4abde7c6bc608063a0d008b7e40ce32\":338944,\"284b83c9c7935002391129fd97f43db5d7cc2ba0\":123}", - ), - Text( - "```", - ), - Text( - "", - ), - Text( - "`8c212779b4abde7c6bc608063a0d008b7e40ce32` is the hash of the torrent and `338944` its download speed limit in bytes per second; this value will be zero if no limit is applied.", - ), - Text( - "", - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Set torrent download limit", - ), - content: [ - Text( - "", - ), - Text( - "Requires knowing the torrent hash. You can get it from [torrent list](#get-torrent-list).", - ), - Text( - "", - ), - Text( - "```http", - ), - Text( - "POST /api/v2/torrents/setDownloadLimit HTTP/1.1", - ), - Text( - "User-Agent: Fiddler", - ), - Text( - "Host: 127.0.0.1", - ), - Text( - "Cookie: SID=your_sid", - ), - Text( - "Content-Type: application/x-www-form-urlencoded", - ), - Text( - "Content-Length: length", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|284b83c9c7935002391129fd97f43db5d7cc2ba0&limit=131072", - columns: [ - "hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32", - "284b83c9c7935002391129fd97f43db5d7cc2ba0&limit=131072", - ], - }, - split: "```", - rows: [], - }, - ), - Table( - Table { - header: TableRow { - raw: "`hashes` can contain multiple hashes separated by `|` or set to `all`", - columns: [ - "hashes can contain multiple hashes separated by", - "or set to all", - ], - }, - split: "`limit` is the download speed limit in bytes per second you want to set.", - rows: [], - }, - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "200 | All scenarios", - columns: [ - "200", - "All scenarios", - ], - }, - ], - }, - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Set torrent share limit", - ), - content: [ - Text( - "", - ), - Text( - "Requires knowing the torrent hash. You can get it from [torrent list](#get-torrent-list).", - ), - Text( - "", - ), - Text( - "Name: `setShareLimits`", - ), - Text( - "", - ), - Text( - "```http", - ), - Text( - "POST /api/v2/torrents/setShareLimits HTTP/1.1", - ), - Text( - "User-Agent: Fiddler", - ), - Text( - "Host: 127.0.0.1", - ), - Text( - "Cookie: SID=your_sid", - ), - Text( - "Content-Type: application/x-www-form-urlencoded", - ), - Text( - "Content-Length: length", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|284b83c9c7935002391129fd97f43db5d7cc2ba0&ratioLimit=1.0&seedingTimeLimit=60", - columns: [ - "hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32", - "284b83c9c7935002391129fd97f43db5d7cc2ba0&ratioLimit=1.0&seedingTimeLimit=60", - ], - }, - split: "```", - rows: [], - }, - ), - Table( - Table { - header: TableRow { - raw: "`hashes` can contain multiple hashes separated by `|` or set to `all`", - columns: [ - "hashes can contain multiple hashes separated by", - "or set to all", - ], - }, - split: "`ratioLimit` is the max ratio the torrent should be seeded until. `-2` means the global limit should be used, `-1` means no limit.", - rows: [], - }, - ), - Text( - "", - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "200 | All scenarios", - columns: [ - "200", - "All scenarios", - ], - }, - ], - }, - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Get torrent upload limit", - ), - content: [ - Text( - "", - ), - Text( - "Requires knowing the torrent hash. You can get it from [torrent list](#get-torrent-list).", - ), - Text( - "", - ), - Text( - "Name: `uploadLimit`", - ), - Text( - "", - ), - Text( - "```http", - ), - Text( - "POST /api/v2/torrents/uploadLimit HTTP/1.1", - ), - Text( - "User-Agent: Fiddler", - ), - Text( - "Host: 127.0.0.1", - ), - Text( - "Cookie: SID=your_sid", - ), - Text( - "Content-Type: application/x-www-form-urlencoded", - ), - Text( - "Content-Length: length", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|284b83c9c7935002391129fd97f43db5d7cc2ba0", - columns: [ - "hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32", - "284b83c9c7935002391129fd97f43db5d7cc2ba0", - ], - }, - split: "```", - rows: [], - }, - ), - Table( - Table { - header: TableRow { - raw: "`hashes` can contain multiple hashes separated by `|` or set to `all`", - columns: [ - "hashes can contain multiple hashes separated by", - "or set to all", - ], - }, - split: "", - rows: [], - }, - ), - Text( - "", - ), - Text( - "```http", - ), - Text( - "HTTP/1.1 200 OK", - ), - Text( - "content-type: application/json", - ), - Text( - "content-length: length", - ), - Text( - "", - ), - Text( - "{\"8c212779b4abde7c6bc608063a0d008b7e40ce32\":338944,\"284b83c9c7935002391129fd97f43db5d7cc2ba0\":123}", - ), - Text( - "```", - ), - Text( - "", - ), - Text( - "`8c212779b4abde7c6bc608063a0d008b7e40ce32` is the hash of the torrent in the request and `338944` its upload speed limit in bytes per second; this value will be zero if no limit is applied.", - ), - Text( - "", - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Set torrent upload limit", - ), - content: [ - Text( - "", - ), - Text( - "Requires knowing the torrent hash. You can get it from [torrent list](#get-torrent-list).", - ), - Text( - "", - ), - Text( - "Name: `setUploadLimit`", - ), - Text( - "", - ), - Text( - "```http", - ), - Text( - "POST /api/v2/torrents/setUploadLimit HTTP/1.1", - ), - Text( - "User-Agent: Fiddler", - ), - Text( - "Host: 127.0.0.1", - ), - Text( - "Cookie: SID=your_sid", - ), - Text( - "Content-Type: application/x-www-form-urlencoded", - ), - Text( - "Content-Length: length", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|284b83c9c7935002391129fd97f43db5d7cc2ba0&limit=131072", - columns: [ - "hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32", - "284b83c9c7935002391129fd97f43db5d7cc2ba0&limit=131072", - ], - }, - split: "```", - rows: [], - }, - ), - Table( - Table { - header: TableRow { - raw: "`hashes` can contain multiple hashes separated by `|` or set to `all`", - columns: [ - "hashes can contain multiple hashes separated by", - "or set to all", - ], - }, - split: "`limit` is the upload speed limit in bytes per second you want to set.", - rows: [], - }, - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "200 | All scenarios", - columns: [ - "200", - "All scenarios", - ], - }, - ], - }, - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Set torrent location", - ), - content: [ - Text( - "", - ), - Text( - "Requires knowing the torrent hash. You can get it from [torrent list](#get-torrent-list).", - ), - Text( - "", - ), - Text( - "Name: `setLocation`", - ), - Text( - "", - ), - Text( - "```http", - ), - Text( - "POST /api/v2/torrents/setLocation HTTP/1.1", - ), - Text( - "User-Agent: Fiddler", - ), - Text( - "Host: 127.0.0.1", - ), - Text( - "Cookie: SID=your_sid", - ), - Text( - "Content-Type: application/x-www-form-urlencoded", - ), - Text( - "Content-Length: length", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|284b83c9c7935002391129fd97f43db5d7cc2ba0&location=/mnt/nfs/media", - columns: [ - "hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32", - "284b83c9c7935002391129fd97f43db5d7cc2ba0&location=/mnt/nfs/media", - ], - }, - split: "```", - rows: [], - }, - ), - Table( - Table { - header: TableRow { - raw: "`hashes` can contain multiple hashes separated by `|` or set to `all`", - columns: [ - "hashes can contain multiple hashes separated by", - "or set to all", - ], - }, - split: "`location` is the location to download the torrent to. If the location doesn't exist, the torrent's location is unchanged.", - rows: [], - }, - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "400 | Save path is empty", - columns: [ - "400", - "Save path is empty", - ], - }, - TableRow { - raw: "403 | User does not have write access to directory", - columns: [ - "403", - "User does not have write access to directory", - ], - }, - TableRow { - raw: "409 | Unable to create save path directory", - columns: [ - "409", - "Unable to create save path directory", - ], - }, - TableRow { - raw: "200 | All other scenarios", - columns: [ - "200", - "All other scenarios", - ], - }, - ], - }, - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Set torrent name", - ), - content: [ - Text( - "", - ), - Text( - "Requires knowing the torrent hash. You can get it from [torrent list](#get-torrent-list).", - ), - Text( - "", - ), - Text( - "Name: `rename`", - ), - Text( - "", - ), - Text( - "```http", - ), - Text( - "POST /api/v2/torrents/rename HTTP/1.1", - ), - Text( - "User-Agent: Fiddler", - ), - Text( - "Host: 127.0.0.1", - ), - Text( - "Cookie: SID=your_sid", - ), - Text( - "Content-Type: application/x-www-form-urlencoded", - ), - Text( - "Content-Length: length", - ), - Text( - "", - ), - Text( - "hash=8c212779b4abde7c6bc608063a0d008b7e40ce32&name=This%20is%20a%20test", - ), - Text( - "```", - ), - Text( - "", - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "404 | Torrent hash is invalid", - columns: [ - "404", - "Torrent hash is invalid", - ], - }, - TableRow { - raw: "409 | Torrent name is empty", - columns: [ - "409", - "Torrent name is empty", - ], - }, - TableRow { - raw: "200 | All other scenarios", - columns: [ - "200", - "All other scenarios", - ], - }, - ], - }, - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Set torrent category", - ), - content: [ - Text( - "", - ), - Text( - "Requires knowing the torrent hash. You can get it from [torrent list](#get-torrent-list).", - ), - Text( - "", - ), - Text( - "Name: `setCategory`", - ), - Text( - "", - ), - Text( - "```http", - ), - Text( - "POST /api/v2/torrents/setCategory HTTP/1.1", - ), - Text( - "User-Agent: Fiddler", - ), - Text( - "Host: 127.0.0.1", - ), - Text( - "Cookie: SID=your_sid", - ), - Text( - "Content-Type: application/x-www-form-urlencoded", - ), - Text( - "Content-Length: length", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|284b83c9c7935002391129fd97f43db5d7cc2ba0&category=CategoryName", - columns: [ - "hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32", - "284b83c9c7935002391129fd97f43db5d7cc2ba0&category=CategoryName", - ], - }, - split: "```", - rows: [], - }, - ), - Table( - Table { - header: TableRow { - raw: "`hashes` can contain multiple hashes separated by `|` or set to `all`", - columns: [ - "hashes can contain multiple hashes separated by", - "or set to all", - ], - }, - split: "", - rows: [], - }, - ), - Text( - "", - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "409 | Category name does not exist", - columns: [ - "409", - "Category name does not exist", - ], - }, - TableRow { - raw: "200 | All other scenarios", - columns: [ - "200", - "All other scenarios", - ], - }, - ], - }, - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Get all categories", - ), - content: [ - Text( - "", - ), - Text( - "Name: `categories`", - ), - Text( - "", - ), - Text( - "Parameters:", - ), - Text( - "", - ), - Text( - "None", - ), - Text( - "", - ), - Text( - "Returns all categories in JSON format, e.g.:", - ), - Text( - "", - ), - Text( - "```JSON", - ), - Text( - "{", - ), - Text( - " \"Video\": {", - ), - Text( - " \"name\": \"Video\",", - ), - Text( - " \"savePath\": \"/home/user/torrents/video/\"", - ), - Text( - " },", - ), - Text( - " \"eBooks\": {", - ), - Text( - " \"name\": \"eBooks\",", - ), - Text( - " \"savePath\": \"/home/user/torrents/eBooks/\"", - ), - Text( - " }", - ), - Text( - "}", - ), - Text( - "```", - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "200 | All scenarios", - columns: [ - "200", - "All scenarios", - ], - }, - ], - }, - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Add new category", - ), - content: [ - Text( - "", - ), - Text( - "Name: `createCategory`", - ), - Text( - "", - ), - Text( - "```http", - ), - Text( - "POST /api/v2/torrents/createCategory HTTP/1.1", - ), - Text( - "User-Agent: Fiddler", - ), - Text( - "Host: 127.0.0.1", - ), - Text( - "Cookie: SID=your_sid", - ), - Text( - "Content-Type: application/x-www-form-urlencoded", - ), - Text( - "Content-Length: length", - ), - Text( - "", - ), - Text( - "category=CategoryName&savePath=/path/to/dir", - ), - Text( - "```", - ), - Text( - "", - ), - Text( - "`category` is the category you want to create.", - ), - Text( - "", - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "400 | Category name is empty", - columns: [ - "400", - "Category name is empty", - ], - }, - TableRow { - raw: "409 | Category name is invalid", - columns: [ - "409", - "Category name is invalid", - ], - }, - TableRow { - raw: "200 | All other scenarios", - columns: [ - "200", - "All other scenarios", - ], - }, - ], - }, - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Edit category", - ), - content: [ - Text( - "", - ), - Text( - "Name: `editCategory`", - ), - Text( - "", - ), - Text( - "```http", - ), - Text( - "POST /api/v2/torrents/editCategory HTTP/1.1", - ), - Text( - "User-Agent: Fiddler", - ), - Text( - "Host: 127.0.0.1", - ), - Text( - "Cookie: SID=your_sid", - ), - Text( - "Content-Type: application/x-www-form-urlencoded", - ), - Text( - "Content-Length: length", - ), - Text( - "", - ), - Text( - "category=CategoryName&savePath=/path/to/save/torrents/to", - ), - Text( - "```", - ), - Text( - "", - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "400 | Category name is empty", - columns: [ - "400", - "Category name is empty", - ], - }, - TableRow { - raw: "409 | Category editing failed", - columns: [ - "409", - "Category editing failed", - ], - }, - TableRow { - raw: "200 | All other scenarios", - columns: [ - "200", - "All other scenarios", - ], - }, - ], - }, - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Remove categories", - ), - content: [ - Text( - "", - ), - Text( - "Name: `removeCategories`", - ), - Text( - "", - ), - Text( - "```http", - ), - Text( - "POST /api/v2/torrents/removeCategories HTTP/1.1", - ), - Text( - "User-Agent: Fiddler", - ), - Text( - "Host: 127.0.0.1", - ), - Text( - "Cookie: SID=your_sid", - ), - Text( - "Content-Type: application/x-www-form-urlencoded", - ), - Text( - "Content-Length: length", - ), - Text( - "", - ), - Text( - "categories=Category1%0ACategory2", - ), - Text( - "```", - ), - Text( - "", - ), - Text( - "`categories` can contain multiple cateogies separated by `\\n` (%0A urlencoded)", - ), - Text( - "", - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "200 | All scenarios", - columns: [ - "200", - "All scenarios", - ], - }, - ], - }, - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Add torrent tags", - ), - content: [ - Text( - "", - ), - Text( - "Requires knowing the torrent hash. You can get it from [torrent list](#get-torrent-list).", - ), - Text( - "", - ), - Text( - "Name: `addTags`", - ), - Text( - "", - ), - Text( - "```http", - ), - Text( - "POST /api/v2/torrents/addTags HTTP/1.1", - ), - Text( - "User-Agent: Fiddler", - ), - Text( - "Host: 127.0.0.1", - ), - Text( - "Cookie: SID=your_sid", - ), - Text( - "Content-Type: application/x-www-form-urlencoded", - ), - Text( - "Content-Length: length", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|284b83c9c7935002391129fd97f43db5d7cc2ba0&tags=TagName1,TagName2", - columns: [ - "hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32", - "284b83c9c7935002391129fd97f43db5d7cc2ba0&tags=TagName1,TagName2", - ], - }, - split: "```", - rows: [], - }, - ), - Table( - Table { - header: TableRow { - raw: "`hashes` can contain multiple hashes separated by `|` or set to `all`", - columns: [ - "hashes can contain multiple hashes separated by", - "or set to all", - ], - }, - split: "", - rows: [], - }, - ), - Text( - "", - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "200 | All scenarios", - columns: [ - "200", - "All scenarios", - ], - }, - ], - }, - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Remove torrent tags", - ), - content: [ - Text( - "", - ), - Text( - "Requires knowing the torrent hash. You can get it from [torrent list](#get-torrent-list).", - ), - Text( - "", - ), - Text( - "Name: `removeTags`", - ), - Text( - "", - ), - Text( - "```http", - ), - Text( - "POST /api/v2/torrents/removeTags HTTP/1.1", - ), - Text( - "User-Agent: Fiddler", - ), - Text( - "Host: 127.0.0.1", - ), - Text( - "Cookie: SID=your_sid", - ), - Text( - "Content-Type: application/x-www-form-urlencoded", - ), - Text( - "Content-Length: length", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|284b83c9c7935002391129fd97f43db5d7cc2ba0&tags=TagName1,TagName2", - columns: [ - "hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32", - "284b83c9c7935002391129fd97f43db5d7cc2ba0&tags=TagName1,TagName2", - ], - }, - split: "```", - rows: [], - }, - ), - Table( - Table { - header: TableRow { - raw: "`hashes` can contain multiple hashes separated by `|` or set to `all`", - columns: [ - "hashes can contain multiple hashes separated by", - "or set to all", - ], - }, - split: "", - rows: [], - }, - ), - Text( - "Empty list removes all tags from relevant torrents.", - ), - Text( - "", - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "200 | All scenarios", - columns: [ - "200", - "All scenarios", - ], - }, - ], - }, - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Get all tags", - ), - content: [ - Text( - "", - ), - Text( - "Name: `tags`", - ), - Text( - "", - ), - Text( - "Parameters:", - ), - Text( - "", - ), - Text( - "None", - ), - Text( - "", - ), - Text( - "Returns all tags in JSON format, e.g.:", - ), - Text( - "", - ), - Text( - "```JSON", - ), - Text( - "[", - ), - Text( - " \"Tag 1\",", - ), - Text( - " \"Tag 2\"", - ), - Text( - "]", - ), - Text( - "```", - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "200 | All scenarios", - columns: [ - "200", - "All scenarios", - ], - }, - ], - }, - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Create tags", - ), - content: [ - Text( - "", - ), - Text( - "Name: `createTags`", - ), - Text( - "", - ), - Text( - "```http", - ), - Text( - "POST /api/v2/torrents/createTags HTTP/1.1", - ), - Text( - "User-Agent: Fiddler", - ), - Text( - "Host: 127.0.0.1", - ), - Text( - "Cookie: SID=your_sid", - ), - Text( - "Content-Type: application/x-www-form-urlencoded", - ), - Text( - "Content-Length: length", - ), - Text( - "", - ), - Text( - "tags=TagName1,TagName2", - ), - Text( - "```", - ), - Text( - "`tags` is a list of tags you want to create.", - ), - Text( - "Can contain multiple tags separated by `,`.", - ), - Text( - "", - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "200 | All scenarios", - columns: [ - "200", - "All scenarios", - ], - }, - ], - }, - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Delete tags", - ), - content: [ - Text( - "", - ), - Text( - "Name: `deleteTags`", - ), - Text( - "", - ), - Text( - "```http", - ), - Text( - "POST /api/v2/torrents/deleteTags HTTP/1.1", - ), - Text( - "User-Agent: Fiddler", - ), - Text( - "Host: 127.0.0.1", - ), - Text( - "Cookie: SID=your_sid", - ), - Text( - "Content-Type: application/x-www-form-urlencoded", - ), - Text( - "Content-Length: length", - ), - Text( - "", - ), - Text( - "tags=TagName1,TagName2", - ), - Text( - "```", - ), - Text( - "", - ), - Text( - "`tags` is a list of tags you want to delete.", - ), - Text( - "Can contain multiple tags separated by `,`.", - ), - Text( - "", - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "200 | All scenarios", - columns: [ - "200", - "All scenarios", - ], - }, - ], - }, - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Set automatic torrent management", - ), - content: [ - Text( - "", - ), - Text( - "Requires knowing the torrent hash. You can get it from [torrent list](#get-torrent-list).", - ), - Text( - "", - ), - Text( - "Name: `setAutoManagement`", - ), - Text( - "", - ), - Text( - "```http", - ), - Text( - "POST /api/v2/torrents/setAutoManagement HTTP/1.1", - ), - Text( - "User-Agent: Fiddler", - ), - Text( - "Host: 127.0.0.1", - ), - Text( - "Cookie: SID=your_sid", - ), - Text( - "Content-Type: application/x-www-form-urlencoded", - ), - Text( - "Content-Length: length", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|284b83c9c7935002391129fd97f43db5d7cc2ba0&enable=true", - columns: [ - "hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32", - "284b83c9c7935002391129fd97f43db5d7cc2ba0&enable=true", - ], - }, - split: "```", - rows: [], - }, - ), - Table( - Table { - header: TableRow { - raw: "`hashes` can contain multiple hashes separated by `|` or set to `all`", - columns: [ - "hashes can contain multiple hashes separated by", - "or set to all", - ], - }, - split: "`enable` is a boolean, affects the torrents listed in `hashes`, default is `false`", - rows: [], - }, - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "200 | All scenarios", - columns: [ - "200", - "All scenarios", - ], - }, - ], - }, - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Toggle sequential download", - ), - content: [ - Text( - "", - ), - Text( - "Requires knowing the torrent hash. You can get it from [torrent list](#get-torrent-list).", - ), - Text( - "", - ), - Text( - "Name: `toggleSequentialDownload`", - ), - Text( - "", - ), - Asterix( - "Parameters:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Parameter | Type | Description", - columns: [ - "Parameter", - "Type", - "Description", - ], - }, - split: "------------|----------|------------", - rows: [ - TableRow { - raw: "`hashes` | string | The hashes of the torrents you want to toggle sequential download for. `hashes` can contain multiple hashes separated by `\\|`, to toggle sequential download for multiple torrents, or set to `all`, to toggle sequential download for all torrents.", - columns: [ - "hashes", - "string", - "The hashes of the torrents you want to toggle sequential download for. hashes can contain multiple hashes separated by \\", - ", to toggle sequential download for multiple torrents, or set to all, to toggle sequential download for all torrents.", - ], - }, - ], - }, - ), - Text( - "Example:", - ), - Text( - "", - ), - Text( - "```http", - ), - Table( - Table { - header: TableRow { - raw: "/api/v2/torrents/toggleSequentialDownload?hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|54eddd830a5b58480a6143d616a97e3a6c23c439", - columns: [ - "/api/v2/torrents/toggleSequentialDownload?hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32", - "54eddd830a5b58480a6143d616a97e3a6c23c439", - ], - }, - split: "```", - rows: [], - }, - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "200 | All scenarios", - columns: [ - "200", - "All scenarios", - ], - }, - ], - }, - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Set first/last piece priority", - ), - content: [ - Text( - "", - ), - Text( - "Requires knowing the torrent hash. You can get it from [torrent list](#get-torrent-list).", - ), - Text( - "", - ), - Text( - "Name: `toggleFirstLastPiecePrio`", - ), - Text( - "", - ), - Asterix( - "Parameters:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Parameter | Type | Description", - columns: [ - "Parameter", - "Type", - "Description", - ], - }, - split: "------------|----------|------------", - rows: [ - TableRow { - raw: "`hashes` | string | The hashes of the torrents you want to toggle the first/last piece priority for. `hashes` can contain multiple hashes separated by `\\|`, to toggle the first/last piece priority for multiple torrents, or set to `all`, to toggle the first/last piece priority for all torrents.", - columns: [ - "hashes", - "string", - "The hashes of the torrents you want to toggle the first/last piece priority for. hashes can contain multiple hashes separated by \\", - ", to toggle the first/last piece priority for multiple torrents, or set to all, to toggle the first/last piece priority for all torrents.", - ], - }, - ], - }, - ), - Text( - "Example:", - ), - Text( - "", - ), - Text( - "```http", - ), - Table( - Table { - header: TableRow { - raw: "/api/v2/torrents/toggleFirstLastPiecePrio?hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|54eddd830a5b58480a6143d616a97e3a6c23c439", - columns: [ - "/api/v2/torrents/toggleFirstLastPiecePrio?hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32", - "54eddd830a5b58480a6143d616a97e3a6c23c439", - ], - }, - split: "```", - rows: [], - }, - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "200 | All scenarios", - columns: [ - "200", - "All scenarios", - ], - }, - ], - }, - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Set force start", - ), - content: [ - Text( - "", - ), - Text( - "Requires knowing the torrent hash. You can get it from [torrent list](#get-torrent-list).", - ), - Text( - "", - ), - Text( - "Name: `setForceStart`", - ), - Text( - "", - ), - Text( - "```http", - ), - Text( - "POST /api/v2/torrents/setForceStart HTTP/1.1", - ), - Text( - "User-Agent: Fiddler", - ), - Text( - "Host: 127.0.0.1", - ), - Text( - "Cookie: SID=your_sid", - ), - Text( - "Content-Type: application/x-www-form-urlencoded", - ), - Text( - "Content-Length: length", - ), - Text( - "", - ), - Text( - "hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32?value=true", - ), - Text( - "```", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "`hashes` can contain multiple hashes separated by `|` or set to `all`", - columns: [ - "hashes can contain multiple hashes separated by", - "or set to all", - ], - }, - split: "`value` is a boolean, affects the torrents listed in `hashes`, default is `false`", - rows: [], - }, - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "200 | All scenarios", - columns: [ - "200", - "All scenarios", - ], - }, - ], - }, - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Set super seeding", - ), - content: [ - Text( - "", - ), - Text( - "Requires knowing the torrent hash. You can get it from [torrent list](#get-torrent-list).", - ), - Text( - "", - ), - Text( - "Name: `setSuperSeeding`", - ), - Text( - "", - ), - Text( - "```http", - ), - Text( - "POST /api/v2/torrents/setSuperSeeding HTTP/1.1", - ), - Text( - "User-Agent: Fiddler", - ), - Text( - "Host: 127.0.0.1", - ), - Text( - "Cookie: SID=your_sid", - ), - Text( - "Content-Type: application/x-www-form-urlencoded", - ), - Text( - "Content-Length: length", - ), - Text( - "", - ), - Text( - "hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32?value=true", - ), - Text( - "```", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "`hashes` can contain multiple hashes separated by `|` or set to `all`", - columns: [ - "hashes can contain multiple hashes separated by", - "or set to all", - ], - }, - split: "`value` is a boolean, affects the torrents listed in `hashes`, default is `false`", - rows: [], - }, - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "200 | All scenarios", - columns: [ - "200", - "All scenarios", - ], - }, - ], - }, - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Rename file", - ), - content: [ - Text( - "", - ), - Text( - "Name: `renameFile`", - ), - Text( - "", - ), - Asterix( - "Parameters:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Parameter | Type | Description", - columns: [ - "Parameter", - "Type", - "Description", - ], - }, - split: "----------------------------------|----------|------------", - rows: [ - TableRow { - raw: "`hash` | string | The hash of the torrent", - columns: [ - "hash", - "string", - "The hash of the torrent", - ], - }, - TableRow { - raw: "`oldPath` | string | The old path of the torrent", - columns: [ - "oldPath", - "string", - "The old path of the torrent", - ], - }, - TableRow { - raw: "`newPath` | string | The new path to use for the file", - columns: [ - "newPath", - "string", - "The new path to use for the file", - ], - }, - ], - }, - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "400 | Missing `newPath` parameter", - columns: [ - "400", - "Missing newPath parameter", - ], - }, - TableRow { - raw: "409 | Invalid `newPath` or `oldPath`, or `newPath` already in use", - columns: [ - "409", - "Invalid newPath or oldPath, or newPath already in use", - ], - }, - TableRow { - raw: "200 | All other scenarios", - columns: [ - "200", - "All other scenarios", - ], - }, - ], - }, - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Rename folder", - ), - content: [ - Text( - "", - ), - Text( - "Name: `renameFolder`", - ), - Text( - "", - ), - Asterix( - "Parameters:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Parameter | Type | Description", - columns: [ - "Parameter", - "Type", - "Description", - ], - }, - split: "----------------------------------|----------|------------", - rows: [ - TableRow { - raw: "`hash` | string | The hash of the torrent", - columns: [ - "hash", - "string", - "The hash of the torrent", - ], - }, - TableRow { - raw: "`oldPath` | string | The old path of the torrent", - columns: [ - "oldPath", - "string", - "The old path of the torrent", - ], - }, - TableRow { - raw: "`newPath` | string | The new path to use for the file", - columns: [ - "newPath", - "string", - "The new path to use for the file", - ], - }, - ], - }, - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "400 | Missing `newPath` parameter", - columns: [ - "400", - "Missing newPath parameter", - ], - }, - TableRow { - raw: "409 | Invalid `newPath` or `oldPath`, or `newPath` already in use", - columns: [ - "409", - "Invalid newPath or oldPath, or newPath already in use", - ], - }, - TableRow { - raw: "200 | All other scenarios", - columns: [ - "200", - "All other scenarios", - ], - }, - ], - }, - ), - ], - children: [], - }, - ], - }, - TokenTree { - title: Some( - "RSS (experimental)", - ), - content: [ - Text( - "", - ), - Text( - "All RSS API methods are under \"rss\", e.g.: `/api/v2/rss/methodName`.", - ), - Text( - "", - ), - ], - children: [ - TokenTree { - title: Some( - "Add folder", - ), - content: [ - Text( - "", - ), - Text( - "Name: `addFolder`", - ), - Text( - "", - ), - Text( - "Parameters:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Parameter | Type | Description", - columns: [ - "Parameter", - "Type", - "Description", - ], - }, - split: "----------------------------------|---------|------------", - rows: [ - TableRow { - raw: "`path` | string | Full path of added folder (e.g. \"The Pirate Bay\\Top100\")", - columns: [ - "path", - "string", - "Full path of added folder (e.g. \"The Pirate Bay\\Top100\")", - ], - }, - ], - }, - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "409 | Failure to add folder", - columns: [ - "409", - "Failure to add folder", - ], - }, - TableRow { - raw: "200 | All other scenarios", - columns: [ - "200", - "All other scenarios", - ], - }, - ], - }, - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Add feed", - ), - content: [ - Text( - "", - ), - Text( - "Name: `addFeed`", - ), - Text( - "", - ), - Text( - "Parameters:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Parameter | Type | Description", - columns: [ - "Parameter", - "Type", - "Description", - ], - }, - split: "----------------------------------|---------|------------", - rows: [ - TableRow { - raw: "`url` | string | URL of RSS feed (e.g. \"[http://thepiratebay.org/rss//top100/200](http://thepiratebay.org/rss//top100/200)\")", - columns: [ - "url", - "string", - "URL of RSS feed (e.g. \"[http://thepiratebay.org/rss//top100/200](http://thepiratebay.org/rss//top100/200)\")", - ], - }, - TableRow { - raw: "`path` _optional_ | string | Full path of added folder (e.g. \"The Pirate Bay\\Top100\\Video\")", - columns: [ - "path _optional_", - "string", - "Full path of added folder (e.g. \"The Pirate Bay\\Top100\\Video\")", - ], - }, - ], - }, - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "409 | Failure to add feed", - columns: [ - "409", - "Failure to add feed", - ], - }, - TableRow { - raw: "200 | All other scenarios", - columns: [ - "200", - "All other scenarios", - ], - }, - ], - }, - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Remove item", - ), - content: [ - Text( - "", - ), - Text( - "Removes folder or feed.", - ), - Text( - "", - ), - Text( - "Name: `removeItem`", - ), - Text( - "", - ), - Text( - "Parameters:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Parameter | Type | Description", - columns: [ - "Parameter", - "Type", - "Description", - ], - }, - split: "----------------------------------|---------|------------", - rows: [ - TableRow { - raw: "`path` | string | Full path of removed item (e.g. \"The Pirate Bay\\Top100\")", - columns: [ - "path", - "string", - "Full path of removed item (e.g. \"The Pirate Bay\\Top100\")", - ], - }, - ], - }, - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "409 | Failure to remove item", - columns: [ - "409", - "Failure to remove item", - ], - }, - TableRow { - raw: "200 | All other scenarios", - columns: [ - "200", - "All other scenarios", - ], - }, - ], - }, - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Move item", - ), - content: [ - Text( - "", - ), - Text( - "Moves/renames folder or feed.", - ), - Text( - "", - ), - Text( - "Name: `moveItem`", - ), - Text( - "", - ), - Text( - "Parameters:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Parameter | Type | Description", - columns: [ - "Parameter", - "Type", - "Description", - ], - }, - split: "----------------------------------|---------|------------", - rows: [ - TableRow { - raw: "`itemPath` | string | Current full path of item (e.g. \"The Pirate Bay\\Top100\")", - columns: [ - "itemPath", - "string", - "Current full path of item (e.g. \"The Pirate Bay\\Top100\")", - ], - }, - TableRow { - raw: "`destPath` | string | New full path of item (e.g. \"The Pirate Bay\")", - columns: [ - "destPath", - "string", - "New full path of item (e.g. \"The Pirate Bay\")", - ], - }, - ], - }, - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "409 | Failure to move item", - columns: [ - "409", - "Failure to move item", - ], - }, - TableRow { - raw: "200 | All other scenarios", - columns: [ - "200", - "All other scenarios", - ], - }, - ], - }, - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Get all items", - ), - content: [ - Text( - "", - ), - Text( - "Name: `items`", - ), - Text( - "", - ), - Text( - "Parameters:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Parameter | Type | Description", - columns: [ - "Parameter", - "Type", - "Description", - ], - }, - split: "----------------------------------|---------|------------", - rows: [ - TableRow { - raw: "`withData` _optional_ | bool | True if you need current feed articles", - columns: [ - "withData _optional_", - "bool", - "True if you need current feed articles", - ], - }, - ], - }, - ), - Text( - "Returns all RSS items in JSON format, e.g.:", - ), - Text( - "", - ), - Text( - "```JSON", - ), - Text( - "{", - ), - Text( - " \"HD-Torrents.org\": \"https://hd-torrents.org/rss.php\",", - ), - Text( - " \"PowerfulJRE\": \"https://www.youtube.com/feeds/videos.xml?channel_id=UCzQUP1qoWDoEbmsQxvdjxgQ\",", - ), - Text( - " \"The Pirate Bay\": {", - ), - Text( - " \"Audio\": \"https://thepiratebay.org/rss//top100/100\",", - ), - Text( - " \"Video\": \"https://thepiratebay.org/rss//top100/200\"", - ), - Text( - " }", - ), - Text( - "}", - ), - Text( - "```", - ), - Text( - "", - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Mark as read", - ), - content: [ - Text( - "", - ), - Text( - "If `articleId` is provided only the article is marked as read otherwise the whole feed is going to be marked as read.", - ), - Text( - "", - ), - Text( - "Name: `markAsRead`", - ), - Text( - "", - ), - Text( - "Parameters:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Parameter | Type | Description", - columns: [ - "Parameter", - "Type", - "Description", - ], - }, - split: "----------------------------------|---------|------------", - rows: [ - TableRow { - raw: "`itemPath` | string | Current full path of item (e.g. \"The Pirate Bay\\Top100\")", - columns: [ - "itemPath", - "string", - "Current full path of item (e.g. \"The Pirate Bay\\Top100\")", - ], - }, - TableRow { - raw: "`articleId` _optional_ | string | ID of article", - columns: [ - "articleId _optional_", - "string", - "ID of article", - ], - }, - ], - }, - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "200 | All scenarios", - columns: [ - "200", - "All scenarios", - ], - }, - ], - }, - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Refresh item", - ), - content: [ - Text( - "", - ), - Text( - "Refreshes folder or feed.", - ), - Text( - "", - ), - Text( - "Name: `refreshItem`", - ), - Text( - "", - ), - Text( - "Parameters:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Parameter | Type | Description", - columns: [ - "Parameter", - "Type", - "Description", - ], - }, - split: "----------------------------------|---------|------------", - rows: [ - TableRow { - raw: "`itemPath` | string | Current full path of item (e.g. \"The Pirate Bay\\Top100\")", - columns: [ - "itemPath", - "string", - "Current full path of item (e.g. \"The Pirate Bay\\Top100\")", - ], - }, - ], - }, - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "200 | All scenarios", - columns: [ - "200", - "All scenarios", - ], - }, - ], - }, - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Set auto-downloading rule", - ), - content: [ - Text( - "", - ), - Text( - "Name: `setRule`", - ), - Text( - "", - ), - Text( - "Parameters:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Parameter | Type | Description", - columns: [ - "Parameter", - "Type", - "Description", - ], - }, - split: "----------------------------------|---------|------------", - rows: [ - TableRow { - raw: "`ruleName` | string | Rule name (e.g. \"Punisher\")", - columns: [ - "ruleName", - "string", - "Rule name (e.g. \"Punisher\")", - ], - }, - TableRow { - raw: "`ruleDef` | string | JSON encoded rule definition", - columns: [ - "ruleDef", - "string", - "JSON encoded rule definition", - ], - }, - ], - }, - ), - Text( - "Rule definition is JSON encoded dictionary with the following fields:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Field | Type | Description", - columns: [ - "Field", - "Type", - "Description", - ], - }, - split: "----------------------------------|---------|------------", - rows: [ - TableRow { - raw: "`enabled` | bool | Whether the rule is enabled", - columns: [ - "enabled", - "bool", - "Whether the rule is enabled", - ], - }, - TableRow { - raw: "`mustContain` | string | The substring that the torrent name must contain", - columns: [ - "mustContain", - "string", - "The substring that the torrent name must contain", - ], - }, - TableRow { - raw: "`mustNotContain` | string | The substring that the torrent name must not contain", - columns: [ - "mustNotContain", - "string", - "The substring that the torrent name must not contain", - ], - }, - TableRow { - raw: "`useRegex` | bool | Enable regex mode in \"mustContain\" and \"mustNotContain\"", - columns: [ - "useRegex", - "bool", - "Enable regex mode in \"mustContain\" and \"mustNotContain\"", - ], - }, - TableRow { - raw: "`episodeFilter` | string | Episode filter definition", - columns: [ - "episodeFilter", - "string", - "Episode filter definition", - ], - }, - TableRow { - raw: "`smartFilter` | bool | Enable smart episode filter", - columns: [ - "smartFilter", - "bool", - "Enable smart episode filter", - ], - }, - TableRow { - raw: "`previouslyMatchedEpisodes` | list | The list of episode IDs already matched by smart filter", - columns: [ - "previouslyMatchedEpisodes", - "list", - "The list of episode IDs already matched by smart filter", - ], - }, - TableRow { - raw: "`affectedFeeds` | list | The feed URLs the rule applied to", - columns: [ - "affectedFeeds", - "list", - "The feed URLs the rule applied to", - ], - }, - TableRow { - raw: "`ignoreDays` | number | Ignore sunsequent rule matches", - columns: [ - "ignoreDays", - "number", - "Ignore sunsequent rule matches", - ], - }, - TableRow { - raw: "`lastMatch` | string | The rule last match time", - columns: [ - "lastMatch", - "string", - "The rule last match time", - ], - }, - TableRow { - raw: "`addPaused` | bool | Add matched torrent in paused mode", - columns: [ - "addPaused", - "bool", - "Add matched torrent in paused mode", - ], - }, - TableRow { - raw: "`assignedCategory` | string | Assign category to the torrent", - columns: [ - "assignedCategory", - "string", - "Assign category to the torrent", - ], - }, - TableRow { - raw: "`savePath` | string | Save torrent to the given directory", - columns: [ - "savePath", - "string", - "Save torrent to the given directory", - ], - }, - ], - }, - ), - Text( - "E.g.:", - ), - Text( - "", - ), - Text( - "```JSON", - ), - Text( - "{", - ), - Text( - " \"enabled\": false,", - ), - Text( - " \"mustContain\": \"The *Punisher*\",", - ), - Text( - " \"mustNotContain\": \"\",", - ), - Text( - " \"useRegex\": false,", - ), - Text( - " \"episodeFilter\": \"1x01-;\",", - ), - Text( - " \"smartFilter\": false,", - ), - Text( - " \"previouslyMatchedEpisodes\": [", - ), - Text( - " ],", - ), - Text( - " \"affectedFeeds\": [", - ), - Text( - " \"http://showrss.info/user/134567.rss?magnets=true\"", - ), - Text( - " ],", - ), - Text( - " \"ignoreDays\": 0,", - ), - Text( - " \"lastMatch\": \"20 Nov 2017 09:05:11\",", - ), - Text( - " \"addPaused\": true,", - ), - Text( - " \"assignedCategory\": \"\",", - ), - Text( - " \"savePath\": \"C:/Users/JohnDoe/Downloads/Punisher\"", - ), - Text( - "}", - ), - Text( - "```", - ), - Text( - "", - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Rename auto-downloading rule", - ), - content: [ - Text( - "", - ), - Text( - "Name: `renameRule`", - ), - Text( - "", - ), - Text( - "Parameters:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Parameter | Type | Description", - columns: [ - "Parameter", - "Type", - "Description", - ], - }, - split: "----------------------------------|---------|------------", - rows: [ - TableRow { - raw: "`ruleName` | string | Rule name (e.g. \"Punisher\")", - columns: [ - "ruleName", - "string", - "Rule name (e.g. \"Punisher\")", - ], - }, - TableRow { - raw: "`newRuleName` | string | New rule name (e.g. \"The Punisher\")", - columns: [ - "newRuleName", - "string", - "New rule name (e.g. \"The Punisher\")", - ], - }, - ], - }, - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "200 | All scenarios", - columns: [ - "200", - "All scenarios", - ], - }, - ], - }, - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Remove auto-downloading rule", - ), - content: [ - Text( - "", - ), - Text( - "Name: `removeRule`", - ), - Text( - "", - ), - Text( - "Parameters:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Parameter | Type | Description", - columns: [ - "Parameter", - "Type", - "Description", - ], - }, - split: "----------------------------------|---------|------------", - rows: [ - TableRow { - raw: "`ruleName` | string | Rule name (e.g. \"Punisher\")", - columns: [ - "ruleName", - "string", - "Rule name (e.g. \"Punisher\")", - ], - }, - ], - }, - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "200 | All scenarios", - columns: [ - "200", - "All scenarios", - ], - }, - ], - }, - ), - Text( - "", - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Get all auto-downloading rules", - ), - content: [ - Text( - "", - ), - Text( - "Name: `rules`", - ), - Text( - "", - ), - Text( - "Returns all auto-downloading rules in JSON format, e.g.:", - ), - Text( - "", - ), - Text( - "```JSON", - ), - Text( - "{", - ), - Text( - " \"The Punisher\": {", - ), - Text( - " \"enabled\": false,", - ), - Text( - " \"mustContain\": \"The *Punisher*\",", - ), - Text( - " \"mustNotContain\": \"\",", - ), - Text( - " \"useRegex\": false,", - ), - Text( - " \"episodeFilter\": \"1x01-;\",", - ), - Text( - " \"smartFilter\": false,", - ), - Text( - " \"previouslyMatchedEpisodes\": [", - ), - Text( - " ],", - ), - Text( - " \"affectedFeeds\": [", - ), - Text( - " \"http://showrss.info/user/134567.rss?magnets=true\"", - ), - Text( - " ],", - ), - Text( - " \"ignoreDays\": 0,", - ), - Text( - " \"lastMatch\": \"20 Nov 2017 09:05:11\",", - ), - Text( - " \"addPaused\": true,", - ), - Text( - " \"assignedCategory\": \"\",", - ), - Text( - " \"savePath\": \"C:/Users/JohnDoe/Downloads/Punisher\"", - ), - Text( - " }", - ), - Text( - "}", - ), - Text( - "```", - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "200 | All scenarios", - columns: [ - "200", - "All scenarios", - ], - }, - ], - }, - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Get all articles matching a rule", - ), - content: [ - Text( - "", - ), - Text( - "Name: `matchingArticles`", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Parameter | Type | Description", - columns: [ - "Parameter", - "Type", - "Description", - ], - }, - split: "----------------------------------|---------|------------", - rows: [ - TableRow { - raw: "`ruleName` | string | Rule name (e.g. \"Linux\")", - columns: [ - "ruleName", - "string", - "Rule name (e.g. \"Linux\")", - ], - }, - ], - }, - ), - Text( - "", - ), - Text( - "Returns all articles that match a rule by feed name in JSON format, e.g.:", - ), - Text( - "", - ), - Text( - "```JSON", - ), - Text( - "{", - ), - Text( - " \"DistroWatch\":[", - ), - Text( - " \"sparkylinux-5.11-i686-minimalgui.iso.torrent\",", - ), - Text( - " \"sparkylinux-5.11-x86_64-minimalgui.iso.torrent\",", - ), - Text( - " \"sparkylinux-5.11-i686-xfce.iso.torrent\",", - ), - Text( - " \"bluestar-linux-5.6.3-2020.04.09-x86_64.iso.torrent\",", - ), - Text( - " \"robolinux64-mate3d-v10.10.iso.torrent\",", - ), - Text( - " ],", - ), - Text( - " \"Linuxtracker\":[", - ), - Text( - " \"[Alpine Linux] alpine-extended-3.11.6\",", - ), - Text( - " \"[Alpine Linux] alpine-standard-3.11.6\",", - ), - Text( - " \"[Linuxfx] linuxfx10-wxs-lts-beta5.iso\",", - ), - Text( - " \"[Linux Lite] linux-lite-5.0-rc1-64bit.iso (MULTI)\",", - ), - Text( - " \"[Scientific Linux] SL-7.8-x86_64-Pack\",", - ), - Text( - " \"[NixOS] nixos-plasma5-20.03.1418.5272327b81e-x86_64-linux.iso\"", - ), - Text( - " ]", - ), - Text( - "}", - ), - Text( - "```", - ), - Text( - "", - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "200 | All scenarios", - columns: [ - "200", - "All scenarios", - ], - }, - ], - }, - ), - Text( - "", - ), - ], - children: [], - }, - ], - }, - TokenTree { - title: Some( - "Search", - ), - content: [ - Text( - "", - ), - Text( - "All Search API methods are under \"search\", e.g.: `/api/v2/search/methodName`.", - ), - Text( - "", - ), - ], - children: [ - TokenTree { - title: Some( - "Start search", - ), - content: [ - Text( - "", - ), - Text( - "Name: `start`", - ), - Text( - "", - ), - Asterix( - "Parameters:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Parameter | Type | Description", - columns: [ - "Parameter", - "Type", - "Description", - ], - }, - split: "----------------------------------|---------|------------", - rows: [ - TableRow { - raw: "`pattern` | string | Pattern to search for (e.g. \"Ubuntu 18.04\")", - columns: [ - "pattern", - "string", - "Pattern to search for (e.g. \"Ubuntu 18.04\")", - ], - }, - TableRow { - raw: "`plugins` | string | Plugins to use for searching (e.g. \"legittorrents\"). Supports multiple plugins separated by `\\|`. Also supports `all` and `enabled`", - columns: [ - "plugins", - "string", - "Plugins to use for searching (e.g. \"legittorrents\"). Supports multiple plugins separated by \\", - ". Also supports all and enabled", - ], - }, - TableRow { - raw: "`category` | string | Categories to limit your search to (e.g. \"legittorrents\"). Available categories depend on the specified `plugins`. Also supports `all`", - columns: [ - "category", - "string", - "Categories to limit your search to (e.g. \"legittorrents\"). Available categories depend on the specified plugins. Also supports all", - ], - }, - ], - }, - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "409 | User has reached the limit of max `Running` searches (currently set to 5)", - columns: [ - "409", - "User has reached the limit of max Running searches (currently set to 5)", - ], - }, - TableRow { - raw: "200 | All other scenarios- see JSON below", - columns: [ - "200", - "All other scenarios- see JSON below", - ], - }, - ], - }, - ), - Text( - "The response is a JSON object with the following fields", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Field | Type | Description", - columns: [ - "Field", - "Type", - "Description", - ], - }, - split: "----------------------------------|---------|------------", - rows: [ - TableRow { - raw: "`id` | number | ID of the search job", - columns: [ - "id", - "number", - "ID of the search job", - ], - }, - ], - }, - ), - Text( - "Example:", - ), - Text( - "", - ), - Text( - "```JSON", - ), - Text( - "{", - ), - Text( - " \"id\": 12345", - ), - Text( - "}", - ), - Text( - "```", - ), - Text( - "", - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Stop search", - ), - content: [ - Text( - "", - ), - Text( - "Name: `stop`", - ), - Text( - "", - ), - Asterix( - "Parameters:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Parameter | Type | Description", - columns: [ - "Parameter", - "Type", - "Description", - ], - }, - split: "----------------------------------|---------|------------", - rows: [ - TableRow { - raw: "`id` | number | ID of the search job", - columns: [ - "id", - "number", - "ID of the search job", - ], - }, - ], - }, - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "404 | Search job was not found", - columns: [ - "404", - "Search job was not found", - ], - }, - TableRow { - raw: "200 | All other scenarios", - columns: [ - "200", - "All other scenarios", - ], - }, - ], - }, - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Get search status", - ), - content: [ - Text( - "", - ), - Text( - "Name: `status`", - ), - Text( - "", - ), - Asterix( - "Parameters:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Parameter | Type | Description", - columns: [ - "Parameter", - "Type", - "Description", - ], - }, - split: "----------------------------------|---------|------------", - rows: [ - TableRow { - raw: "`id` _optional_ | number | ID of the search job. If not specified, all search jobs are returned", - columns: [ - "id _optional_", - "number", - "ID of the search job. If not specified, all search jobs are returned", - ], - }, - ], - }, - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "404 | Search job was not found", - columns: [ - "404", - "Search job was not found", - ], - }, - TableRow { - raw: "200 | All other scenarios- see JSON below", - columns: [ - "200", - "All other scenarios- see JSON below", - ], - }, - ], - }, - ), - Text( - "The response is a JSON array of objects containing the following fields", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Field | Type | Description", - columns: [ - "Field", - "Type", - "Description", - ], - }, - split: "----------------------------------|---------|------------", - rows: [ - TableRow { - raw: "`id` | number | ID of the search job", - columns: [ - "id", - "number", - "ID of the search job", - ], - }, - TableRow { - raw: "`status` | string | Current status of the search job (either `Running` or `Stopped`)", - columns: [ - "status", - "string", - "Current status of the search job (either Running or Stopped)", - ], - }, - TableRow { - raw: "`total` | number | Total number of results. If the status is `Running` this number may contineu to increase", - columns: [ - "total", - "number", - "Total number of results. If the status is Running this number may contineu to increase", - ], - }, - ], - }, - ), - Text( - "Example:", - ), - Text( - "", - ), - Text( - "```JSON", - ), - Text( - "[", - ), - Text( - " {", - ), - Text( - " \"id\": 12345,", - ), - Text( - " \"status\": \"Running\",", - ), - Text( - " \"total\": 170", - ), - Text( - " }", - ), - Text( - "]", - ), - Text( - "```", - ), - Text( - "", - ), - ], - children: [], - }, - TokenTree { - title: Some( - "Get search results", - ), - content: [ - Text( - "", - ), - Text( - "Name: `results`", - ), - Text( - "", - ), - Asterix( - "Parameters:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Parameter | Type | Description", - columns: [ - "Parameter", - "Type", - "Description", - ], - }, - split: "----------------------------------|---------|------------", - rows: [ - TableRow { - raw: "`id` | number | ID of the search job", - columns: [ - "id", - "number", - "ID of the search job", - ], - }, - TableRow { - raw: "`limit` _optional_ | number | max number of results to return. 0 or negative means no limit", - columns: [ - "limit _optional_", - "number", - "max number of results to return. 0 or negative means no limit", - ], - }, - TableRow { - raw: "`offset` _optional_ | number | result to start at. A negative number means count backwards (e.g. `-2` returns the 2 most recent results)", - columns: [ - "offset _optional_", - "number", - "result to start at. A negative number means count backwards (e.g. -2 returns the 2 most recent results)", - ], - }, - ], - }, - ), - Asterix( - "Returns:", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "HTTP Status Code | Scenario", - columns: [ - "HTTP Status Code", - "Scenario", - ], - }, - split: "----------------------------------|---------------------", - rows: [ - TableRow { - raw: "404 | Search job was not found", - columns: [ - "404", - "Search job was not found", - ], - }, - TableRow { - raw: "409 | Offset is too large, or too small (e.g. absolute value of negative number is greater than # results)", - columns: [ - "409", - "Offset is too large, or too small (e.g. absolute value of negative number is greater than # results)", - ], - }, - TableRow { - raw: "200 | All other scenarios- see JSON below", - columns: [ - "200", - "All other scenarios- see JSON below", - ], - }, - ], - }, - ), - Text( - "The response is a JSON object with the following fields", - ), - Text( - "", - ), - Table( - Table { - header: TableRow { - raw: "Field | Type | Description", - columns: [ - "Field", - "Type", - "Description", - ], - }, - split: "----------------------------------|---------|------------", - rows: [], - }, - ), - ], - children: [], - }, - ], - }, - ], -} \ No newline at end of file From 3ba7ee65c8e4cd596d5ff24d151059aa1ddb5774 Mon Sep 17 00:00:00 2001 From: Joel Wachsler Date: Thu, 14 Jul 2022 10:30:31 +0000 Subject: [PATCH 02/47] Add search tests --- .../tests/access_search.rs | 21 +++++++++++++++++++ qbittorrent-web-api-gen/tests/tests.rs | 1 + 2 files changed, 22 insertions(+) create mode 100644 qbittorrent-web-api-gen/tests/access_search.rs diff --git a/qbittorrent-web-api-gen/tests/access_search.rs b/qbittorrent-web-api-gen/tests/access_search.rs new file mode 100644 index 0000000..5dbe996 --- /dev/null +++ b/qbittorrent-web-api-gen/tests/access_search.rs @@ -0,0 +1,21 @@ +use anyhow::Result; +use qbittorrent_web_api_gen::QBittorrentApiGen; + +const USERNAME: &str = "admin"; +const PASSWORD: &str = "adminadmin"; +const BASE_URL: &str = "http://localhost:8080"; + +#[derive(QBittorrentApiGen)] +struct Api {} + +#[tokio::main] +async fn main() -> Result<()> { + let api = Api::login(BASE_URL, USERNAME, PASSWORD).await?; + + let _ = api.search().delete(1).send().await?; + let _ = api.search().plugins().await?; + let _ = api.search().plugins().await?; + let _ = api.search().install_plugin("https://raw.githubusercontent.com/qbittorrent/search-plugins/master/nova3/engines/legittorrents.py").send().await?; + + Ok(()) +} diff --git a/qbittorrent-web-api-gen/tests/tests.rs b/qbittorrent-web-api-gen/tests/tests.rs index 61f2cd2..433c64b 100644 --- a/qbittorrent-web-api-gen/tests/tests.rs +++ b/qbittorrent-web-api-gen/tests/tests.rs @@ -19,4 +19,5 @@ fn tests() { t.pass("tests/add_torrent.rs"); t.pass("tests/another_struct_name.rs"); t.pass("tests/access_impl_types.rs"); + t.pass("tests/search_types.rs"); } From 9b192a92f21b59ad6b6b11301fa12b2da376bc66 Mon Sep 17 00:00:00 2001 From: Joel Wachsler Date: Thu, 14 Jul 2022 10:32:53 +0000 Subject: [PATCH 03/47] Move md_parser --- qbittorrent-web-api-gen/src/{md_parser.rs => md_parser/mod.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename qbittorrent-web-api-gen/src/{md_parser.rs => md_parser/mod.rs} (100%) diff --git a/qbittorrent-web-api-gen/src/md_parser.rs b/qbittorrent-web-api-gen/src/md_parser/mod.rs similarity index 100% rename from qbittorrent-web-api-gen/src/md_parser.rs rename to qbittorrent-web-api-gen/src/md_parser/mod.rs From 85875abd2b34b2ec6f41a6350dd358764dc8c1bd Mon Sep 17 00:00:00 2001 From: Joel Wachsler Date: Thu, 14 Jul 2022 11:16:03 +0000 Subject: [PATCH 04/47] Split md_parser --- qbittorrent-web-api-gen/Cargo.toml | 6 + .../src/md_parser/md_token.rs | 127 +++++++ qbittorrent-web-api-gen/src/md_parser/mod.rs | 321 +----------------- .../src/md_parser/token_tree.rs | 30 ++ .../src/md_parser/token_tree_factory.rs | 166 +++++++++ .../tests/access_search.rs | 9 +- qbittorrent-web-api-gen/tests/add_torrent.rs | 9 +- .../tests/another_struct_name.rs | 9 +- qbittorrent-web-api-gen/tests/common/mod.rs | 3 + .../tests/default_parameters.rs | 9 +- qbittorrent-web-api-gen/tests/login.rs | 9 +- qbittorrent-web-api-gen/tests/logout.rs | 9 +- qbittorrent-web-api-gen/tests/return_type.rs | 9 +- .../tests/return_type_enum.rs | 11 +- .../tests/return_type_with_optional_params.rs | 11 +- qbittorrent-web-api-gen/tests/tests.rs | 3 +- .../tests/without_parameters.rs | 9 +- 17 files changed, 382 insertions(+), 368 deletions(-) create mode 100644 qbittorrent-web-api-gen/src/md_parser/md_token.rs create mode 100644 qbittorrent-web-api-gen/src/md_parser/token_tree.rs create mode 100644 qbittorrent-web-api-gen/src/md_parser/token_tree_factory.rs create mode 100644 qbittorrent-web-api-gen/tests/common/mod.rs diff --git a/qbittorrent-web-api-gen/Cargo.toml b/qbittorrent-web-api-gen/Cargo.toml index c0fd57f..eaecf5f 100644 --- a/qbittorrent-web-api-gen/Cargo.toml +++ b/qbittorrent-web-api-gen/Cargo.toml @@ -7,10 +7,16 @@ keywords = ["qbittorrent"] repository = "https://github.com/JoelWachsler/qbittorrent-web-api" description = "Generated web api for qBittorrent" exclude = ["*.txt", "tests"] +# we use trybuild instead +autotests = false [lib] proc-macro = true +[[test]] +name = "tests" +path = "tests/tests.rs" + [dependencies] syn = { version = "1.0.98", features = ["extra-traits"]} quote = "1.0.20" diff --git a/qbittorrent-web-api-gen/src/md_parser/md_token.rs b/qbittorrent-web-api-gen/src/md_parser/md_token.rs new file mode 100644 index 0000000..439216e --- /dev/null +++ b/qbittorrent-web-api-gen/src/md_parser/md_token.rs @@ -0,0 +1,127 @@ +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum MdContent { + Text(String), + Asterix(String), + Table(Table), +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Table { + pub header: TableRow, + pub split: String, + pub rows: Vec, +} + +impl Table { + fn raw(&self) -> String { + let mut output = vec![self.header.raw.clone(), self.split.clone()]; + for row in self.rows.clone() { + output.push(row.raw); + } + + output.join("\n") + } +} + +#[derive(Debug, Clone)] +pub struct Header { + pub level: i32, + pub content: String, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct TableRow { + raw: String, + pub columns: Vec, +} + +impl MdContent { + pub fn inner_value_as_string(&self) -> String { + match self { + MdContent::Text(text) => text.into(), + MdContent::Asterix(text) => text.into(), + MdContent::Table(table) => table.raw(), + } + } +} + +#[derive(Debug)] +pub enum MdToken { + Header(Header), + Content(MdContent), +} + +impl MdToken { + fn parse_token(line: &str) -> MdToken { + if line.starts_with('#') { + let mut level = 0; + for char in line.chars() { + if char != '#' { + break; + } + + level += 1; + } + + MdToken::Header(Header { + level, + content: line.trim_matches('#').trim().to_string(), + }) + } else if line.starts_with('*') { + MdToken::Content(MdContent::Asterix( + line.trim_matches('*').trim().to_string(), + )) + } else { + MdToken::Content(MdContent::Text(line.to_string())) + } + } + + pub fn from(content: &str) -> Vec { + let mut output = Vec::new(); + + let mut iter = content.lines(); + while let Some(line) = iter.next() { + // assume this is a table + if line.contains('|') { + let to_columns = |column_line: &str| { + column_line + .replace('`', "") + .split('|') + .map(|s| s.trim().to_string()) + .collect() + }; + + let table_header = TableRow { + raw: line.into(), + columns: to_columns(line), + }; + let table_split = iter.next().unwrap(); + let mut table_rows = Vec::new(); + while let Some(row_line) = iter.next() { + if !row_line.contains('|') { + // we've reached the end of the table, let's go back one step + iter.next_back(); + break; + } + + let table_row = TableRow { + raw: row_line.into(), + columns: to_columns(row_line), + }; + + table_rows.push(table_row); + } + + output.push(MdToken::Content(MdContent::Table(Table { + header: table_header, + split: table_split.to_string(), + rows: table_rows, + }))); + } else { + output.push(MdToken::parse_token(line)); + } + } + + output + } +} diff --git a/qbittorrent-web-api-gen/src/md_parser/mod.rs b/qbittorrent-web-api-gen/src/md_parser/mod.rs index 184e994..08d4769 100644 --- a/qbittorrent-web-api-gen/src/md_parser/mod.rs +++ b/qbittorrent-web-api-gen/src/md_parser/mod.rs @@ -1,316 +1,7 @@ -use std::{cell::RefCell, rc::Rc}; +mod md_token; +mod token_tree; +mod token_tree_factory; -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum MdContent { - Text(String), - Asterix(String), - Table(Table), -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct Table { - pub header: TableRow, - pub split: String, - pub rows: Vec, -} - -impl Table { - fn raw(&self) -> String { - let mut output = vec![self.header.raw.clone(), self.split.clone()]; - for row in self.rows.clone() { - output.push(row.raw); - } - - output.join("\n") - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct TableRow { - raw: String, - pub columns: Vec, -} - -impl MdContent { - pub fn inner_value_as_string(&self) -> String { - match self { - MdContent::Text(text) => text.into(), - MdContent::Asterix(text) => text.into(), - MdContent::Table(table) => table.raw(), - } - } -} - -#[derive(Debug, Clone)] -pub struct Header { - level: i32, - content: String, -} - -/// These are the only relevant tokens we need for the api generation. -#[derive(Debug)] -pub enum MdToken { - Header(Header), - Content(MdContent), -} - -impl MdToken { - fn parse_token(line: &str) -> MdToken { - if line.starts_with('#') { - let mut level = 0; - for char in line.chars() { - if char != '#' { - break; - } - - level += 1; - } - - MdToken::Header(Header { - level, - content: line.trim_matches('#').trim().to_string(), - }) - } else if line.starts_with('*') { - MdToken::Content(MdContent::Asterix( - line.trim_matches('*').trim().to_string(), - )) - } else { - MdToken::Content(MdContent::Text(line.to_string())) - } - } - - fn from(content: &str) -> Vec { - let mut output = Vec::new(); - - let mut iter = content.lines(); - while let Some(line) = iter.next() { - // assume this is a table - if line.contains('|') { - let to_columns = |column_line: &str| { - column_line - .replace('`', "") - .split('|') - .map(|s| s.trim().to_string()) - .collect() - }; - - let table_header = TableRow { - raw: line.into(), - columns: to_columns(line), - }; - let table_split = iter.next().unwrap(); - let mut table_rows = Vec::new(); - while let Some(row_line) = iter.next() { - if !row_line.contains('|') { - // we've reached the end of the table, let's go back one step - iter.next_back(); - break; - } - - let table_row = TableRow { - raw: row_line.into(), - columns: to_columns(row_line), - }; - - table_rows.push(table_row); - } - - output.push(MdToken::Content(MdContent::Table(Table { - header: table_header, - split: table_split.to_string(), - rows: table_rows, - }))); - } else { - output.push(MdToken::parse_token(line)); - } - } - - output - } -} - -#[derive(Debug)] -pub struct TokenTree { - pub title: Option, - pub content: Vec, - pub children: Vec, -} - -impl From> for TokenTree { - fn from(builder: Rc) -> Self { - let children = builder - .children - .clone() - .into_inner() - .into_iter() - .map(|child| child.into()) - .collect::>(); - - let content = builder.content.clone().into_inner(); - - TokenTree { - title: builder.title.clone(), - content, - children, - } - } -} - -#[derive(Debug, Default)] -pub struct TokenTreeFactory { - title: Option, - content: RefCell>, - children: RefCell>>, - level: i32, -} - -impl TokenTreeFactory { - fn new(title: &str, level: i32) -> Self { - Self { - title: if title.is_empty() { - None - } else { - Some(title.to_string()) - }, - level, - ..Default::default() - } - } - - fn add_content(&self, content: MdContent) { - self.content.borrow_mut().push(content); - } - - fn append(&self, child: &Rc) { - self.children.borrow_mut().push(child.clone()); - } - - pub fn create(content: &str) -> TokenTree { - let tokens = MdToken::from(content); - - let mut stack = Vec::new(); - let root = Rc::new(TokenTreeFactory::default()); - stack.push(root.clone()); - - for token in tokens { - match token { - MdToken::Header(Header { level, content }) => { - let new_header = Rc::new(TokenTreeFactory::new(&content, level)); - - // go back until we're at the same or lower level. - while let Some(current) = stack.pop() { - if current.level < level { - current.append(&new_header); - stack.push(current); - break; - } - } - - stack.push(new_header.clone()); - } - MdToken::Content(content) => { - let current = stack.pop().unwrap(); - current.add_content(content); - stack.push(current); - } - } - } - - root.into() - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn should_remove_surrounding_asterix() { - // given - let input = r#" -# A -**B** - "# - .trim_matches('\n') - .trim(); - - // when - let tree = TokenTreeFactory::create(input); - - // then - println!("{:#?}", tree); - let first = tree.children.first().unwrap(); - let content = first.content.first().unwrap(); - assert_eq!(*content, MdContent::Asterix("B".into())); - } - - #[test] - fn should_remove_surrounding_hash() { - // given - let input = r#" -# A # - "# - .trim_matches('\n') - .trim(); - - // when - let tree = TokenTreeFactory::create(input); - - // then - println!("{:#?}", tree); - assert_eq!(tree.children.first().unwrap().title, Some("A".into())); - } - - #[test] - fn single_level() { - // given - let input = r#" -# A -Foo - "# - .trim_matches('\n') - .trim(); - - // when - let tree = TokenTreeFactory::create(input); - - // then - println!("{:#?}", tree); - assert_eq!(tree.title, None); - let first_child = tree.children.first().unwrap(); - assert_eq!(first_child.title, Some("A".into())); - } - - #[test] - fn complex() { - // given - let input = r#" -# A -Foo -## B -# C -## D -Bar - "# - .trim_matches('\n') - .trim(); - - // when - let tree = TokenTreeFactory::create(input); - - // then - println!("{:#?}", tree); - assert_eq!(tree.title, None); - assert_eq!(tree.children.len(), 2); - - let first = tree.children.get(0).unwrap(); - assert_eq!(first.title, Some("A".into())); - assert_eq!(first.children.len(), 1); - assert_eq!(first.children.first().unwrap().title, Some("B".into())); - - let second = tree.children.get(1).unwrap(); - assert_eq!(second.title, Some("C".into())); - assert_eq!(second.children.len(), 1); - assert_eq!(second.children.first().unwrap().title, Some("D".into())); - } -} +pub use md_token::*; +pub use token_tree::TokenTree; +pub use token_tree_factory::TokenTreeFactory; diff --git a/qbittorrent-web-api-gen/src/md_parser/token_tree.rs b/qbittorrent-web-api-gen/src/md_parser/token_tree.rs new file mode 100644 index 0000000..473193b --- /dev/null +++ b/qbittorrent-web-api-gen/src/md_parser/token_tree.rs @@ -0,0 +1,30 @@ +use std::rc::Rc; + +use super::{md_token::MdContent, token_tree_factory::TokenTreeFactory}; + +#[derive(Debug)] +pub struct TokenTree { + pub title: Option, + pub content: Vec, + pub children: Vec, +} + +impl From> for TokenTree { + fn from(builder: Rc) -> Self { + let children = builder + .children + .clone() + .into_inner() + .into_iter() + .map(|child| child.into()) + .collect::>(); + + let content = builder.content.clone().into_inner(); + + TokenTree { + title: builder.title.clone(), + content, + children, + } + } +} diff --git a/qbittorrent-web-api-gen/src/md_parser/token_tree_factory.rs b/qbittorrent-web-api-gen/src/md_parser/token_tree_factory.rs new file mode 100644 index 0000000..f62ebc5 --- /dev/null +++ b/qbittorrent-web-api-gen/src/md_parser/token_tree_factory.rs @@ -0,0 +1,166 @@ +use std::{cell::RefCell, rc::Rc}; + +use super::{ + md_token::{Header, MdContent, MdToken}, + token_tree::TokenTree, +}; + +#[derive(Debug, Default)] +pub struct TokenTreeFactory { + pub title: Option, + pub content: RefCell>, + pub children: RefCell>>, + pub level: i32, +} + +impl TokenTreeFactory { + fn new(title: &str, level: i32) -> Self { + Self { + title: if title.is_empty() { + None + } else { + Some(title.to_string()) + }, + level, + ..Default::default() + } + } + + fn add_content(&self, content: MdContent) { + self.content.borrow_mut().push(content); + } + + fn append(&self, child: &Rc) { + self.children.borrow_mut().push(child.clone()); + } + + pub fn create(content: &str) -> TokenTree { + let tokens = MdToken::from(content); + + let mut stack = Vec::new(); + let root = Rc::new(TokenTreeFactory::default()); + stack.push(root.clone()); + + for token in tokens { + match token { + MdToken::Header(Header { level, content }) => { + let new_header = Rc::new(TokenTreeFactory::new(&content, level)); + + // go back until we're at the same or lower level. + while let Some(current) = stack.pop() { + if current.level < level { + current.append(&new_header); + stack.push(current); + break; + } + } + + stack.push(new_header.clone()); + } + MdToken::Content(content) => { + let current = stack.pop().unwrap(); + current.add_content(content); + stack.push(current); + } + } + } + + root.into() + } +} + + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn should_remove_surrounding_asterix() { + // given + let input = r#" +# A +**B** + "# + .trim_matches('\n') + .trim(); + + // when + let tree = TokenTreeFactory::create(input); + + // then + println!("{:#?}", tree); + let first = tree.children.first().unwrap(); + let content = first.content.first().unwrap(); + assert_eq!(*content, MdContent::Asterix("B".into())); + } + + #[test] + fn should_remove_surrounding_hash() { + // given + let input = r#" +# A # + "# + .trim_matches('\n') + .trim(); + + // when + let tree = TokenTreeFactory::create(input); + + // then + println!("{:#?}", tree); + assert_eq!(tree.children.first().unwrap().title, Some("A".into())); + } + + #[test] + fn single_level() { + // given + let input = r#" +# A +Foo + "# + .trim_matches('\n') + .trim(); + + // when + let tree = TokenTreeFactory::create(input); + + // then + println!("{:#?}", tree); + assert_eq!(tree.title, None); + let first_child = tree.children.first().unwrap(); + assert_eq!(first_child.title, Some("A".into())); + } + + #[test] + fn complex() { + // given + let input = r#" +# A +Foo +## B +# C +## D +Bar + "# + .trim_matches('\n') + .trim(); + + // when + let tree = TokenTreeFactory::create(input); + + // then + println!("{:#?}", tree); + assert_eq!(tree.title, None); + assert_eq!(tree.children.len(), 2); + + let first = tree.children.get(0).unwrap(); + assert_eq!(first.title, Some("A".into())); + assert_eq!(first.children.len(), 1); + assert_eq!(first.children.first().unwrap().title, Some("B".into())); + + let second = tree.children.get(1).unwrap(); + assert_eq!(second.title, Some("C".into())); + assert_eq!(second.children.len(), 1); + assert_eq!(second.children.first().unwrap().title, Some("D".into())); + } +} diff --git a/qbittorrent-web-api-gen/tests/access_search.rs b/qbittorrent-web-api-gen/tests/access_search.rs index 5dbe996..504dbc3 100644 --- a/qbittorrent-web-api-gen/tests/access_search.rs +++ b/qbittorrent-web-api-gen/tests/access_search.rs @@ -1,9 +1,8 @@ -use anyhow::Result; -use qbittorrent_web_api_gen::QBittorrentApiGen; +mod common; -const USERNAME: &str = "admin"; -const PASSWORD: &str = "adminadmin"; -const BASE_URL: &str = "http://localhost:8080"; +use anyhow::Result; +use common::*; +use qbittorrent_web_api_gen::QBittorrentApiGen; #[derive(QBittorrentApiGen)] struct Api {} diff --git a/qbittorrent-web-api-gen/tests/add_torrent.rs b/qbittorrent-web-api-gen/tests/add_torrent.rs index 697fb63..b1a0124 100644 --- a/qbittorrent-web-api-gen/tests/add_torrent.rs +++ b/qbittorrent-web-api-gen/tests/add_torrent.rs @@ -1,9 +1,8 @@ -use anyhow::Result; -use qbittorrent_web_api_gen::QBittorrentApiGen; +mod common; -const USERNAME: &str = "admin"; -const PASSWORD: &str = "adminadmin"; -const BASE_URL: &str = "http://localhost:8080"; +use anyhow::Result; +use common::*; +use qbittorrent_web_api_gen::QBittorrentApiGen; #[derive(QBittorrentApiGen)] struct Api {} diff --git a/qbittorrent-web-api-gen/tests/another_struct_name.rs b/qbittorrent-web-api-gen/tests/another_struct_name.rs index bca720b..7cccbf2 100644 --- a/qbittorrent-web-api-gen/tests/another_struct_name.rs +++ b/qbittorrent-web-api-gen/tests/another_struct_name.rs @@ -1,9 +1,8 @@ -use anyhow::Result; -use qbittorrent_web_api_gen::QBittorrentApiGen; +mod common; -const USERNAME: &str = "admin"; -const PASSWORD: &str = "adminadmin"; -const BASE_URL: &str = "http://localhost:8080"; +use anyhow::Result; +use common::*; +use qbittorrent_web_api_gen::QBittorrentApiGen; #[derive(QBittorrentApiGen)] struct Foo {} diff --git a/qbittorrent-web-api-gen/tests/common/mod.rs b/qbittorrent-web-api-gen/tests/common/mod.rs new file mode 100644 index 0000000..8180627 --- /dev/null +++ b/qbittorrent-web-api-gen/tests/common/mod.rs @@ -0,0 +1,3 @@ +pub const USERNAME: &str = "admin"; +pub const PASSWORD: &str = "adminadmin"; +pub const BASE_URL: &str = "http://localhost:8080"; diff --git a/qbittorrent-web-api-gen/tests/default_parameters.rs b/qbittorrent-web-api-gen/tests/default_parameters.rs index 2617e95..5cd7531 100644 --- a/qbittorrent-web-api-gen/tests/default_parameters.rs +++ b/qbittorrent-web-api-gen/tests/default_parameters.rs @@ -1,9 +1,8 @@ -use anyhow::Result; -use qbittorrent_web_api_gen::QBittorrentApiGen; +mod common; -const USERNAME: &str = "admin"; -const PASSWORD: &str = "adminadmin"; -const BASE_URL: &str = "http://localhost:8080"; +use anyhow::Result; +use common::*; +use qbittorrent_web_api_gen::QBittorrentApiGen; #[derive(QBittorrentApiGen)] struct Api {} diff --git a/qbittorrent-web-api-gen/tests/login.rs b/qbittorrent-web-api-gen/tests/login.rs index fb54bd4..ff9292d 100644 --- a/qbittorrent-web-api-gen/tests/login.rs +++ b/qbittorrent-web-api-gen/tests/login.rs @@ -1,9 +1,8 @@ -use anyhow::Result; -use qbittorrent_web_api_gen::QBittorrentApiGen; +mod common; -const USERNAME: &str = "admin"; -const PASSWORD: &str = "adminadmin"; -const BASE_URL: &str = "http://localhost:8080"; +use anyhow::Result; +use common::*; +use qbittorrent_web_api_gen::QBittorrentApiGen; #[derive(QBittorrentApiGen)] struct Api {} diff --git a/qbittorrent-web-api-gen/tests/logout.rs b/qbittorrent-web-api-gen/tests/logout.rs index 97bfeb9..c002f24 100644 --- a/qbittorrent-web-api-gen/tests/logout.rs +++ b/qbittorrent-web-api-gen/tests/logout.rs @@ -1,9 +1,8 @@ -use anyhow::Result; -use qbittorrent_web_api_gen::QBittorrentApiGen; +mod common; -const USERNAME: &str = "admin"; -const PASSWORD: &str = "adminadmin"; -const BASE_URL: &str = "http://localhost:8080"; +use anyhow::Result; +use common::*; +use qbittorrent_web_api_gen::QBittorrentApiGen; #[derive(QBittorrentApiGen)] struct Api {} diff --git a/qbittorrent-web-api-gen/tests/return_type.rs b/qbittorrent-web-api-gen/tests/return_type.rs index 6c87cab..55a3585 100644 --- a/qbittorrent-web-api-gen/tests/return_type.rs +++ b/qbittorrent-web-api-gen/tests/return_type.rs @@ -1,9 +1,8 @@ -use anyhow::Result; -use qbittorrent_web_api_gen::QBittorrentApiGen; +mod common; -const USERNAME: &str = "admin"; -const PASSWORD: &str = "adminadmin"; -const BASE_URL: &str = "http://localhost:8080"; +use anyhow::Result; +use common::*; +use qbittorrent_web_api_gen::QBittorrentApiGen; #[derive(QBittorrentApiGen)] struct Api {} diff --git a/qbittorrent-web-api-gen/tests/return_type_enum.rs b/qbittorrent-web-api-gen/tests/return_type_enum.rs index c557513..2e37c26 100644 --- a/qbittorrent-web-api-gen/tests/return_type_enum.rs +++ b/qbittorrent-web-api-gen/tests/return_type_enum.rs @@ -1,10 +1,9 @@ -use anyhow::Result; -use qbittorrent_web_api_gen::QBittorrentApiGen; -use tokio::time::{sleep, Duration}; +mod common; -const USERNAME: &str = "admin"; -const PASSWORD: &str = "adminadmin"; -const BASE_URL: &str = "http://localhost:8080"; +use anyhow::Result; +use common::*; +use qbittorrent_web_api_gen::QBittorrentApiGen; +use tokio::time::*; #[derive(QBittorrentApiGen)] struct Api {} diff --git a/qbittorrent-web-api-gen/tests/return_type_with_optional_params.rs b/qbittorrent-web-api-gen/tests/return_type_with_optional_params.rs index c557513..2e37c26 100644 --- a/qbittorrent-web-api-gen/tests/return_type_with_optional_params.rs +++ b/qbittorrent-web-api-gen/tests/return_type_with_optional_params.rs @@ -1,10 +1,9 @@ -use anyhow::Result; -use qbittorrent_web_api_gen::QBittorrentApiGen; -use tokio::time::{sleep, Duration}; +mod common; -const USERNAME: &str = "admin"; -const PASSWORD: &str = "adminadmin"; -const BASE_URL: &str = "http://localhost:8080"; +use anyhow::Result; +use common::*; +use qbittorrent_web_api_gen::QBittorrentApiGen; +use tokio::time::*; #[derive(QBittorrentApiGen)] struct Api {} diff --git a/qbittorrent-web-api-gen/tests/tests.rs b/qbittorrent-web-api-gen/tests/tests.rs index 433c64b..548499f 100644 --- a/qbittorrent-web-api-gen/tests/tests.rs +++ b/qbittorrent-web-api-gen/tests/tests.rs @@ -1,6 +1,7 @@ #[test] fn tests() { let t = trybuild::TestCases::new(); + // --- Auth --- t.pass("tests/login.rs"); t.pass("tests/logout.rs"); @@ -19,5 +20,5 @@ fn tests() { t.pass("tests/add_torrent.rs"); t.pass("tests/another_struct_name.rs"); t.pass("tests/access_impl_types.rs"); - t.pass("tests/search_types.rs"); + // t.pass("tests/search_types.rs"); } diff --git a/qbittorrent-web-api-gen/tests/without_parameters.rs b/qbittorrent-web-api-gen/tests/without_parameters.rs index aa23d4f..47dec5d 100644 --- a/qbittorrent-web-api-gen/tests/without_parameters.rs +++ b/qbittorrent-web-api-gen/tests/without_parameters.rs @@ -1,9 +1,8 @@ -use anyhow::Result; -use qbittorrent_web_api_gen::QBittorrentApiGen; +mod common; -const USERNAME: &str = "admin"; -const PASSWORD: &str = "adminadmin"; -const BASE_URL: &str = "http://localhost:8080"; +use anyhow::Result; +use common::*; +use qbittorrent_web_api_gen::QBittorrentApiGen; #[derive(QBittorrentApiGen)] struct Api {} From 48dda84ea1548ebb7b3790012594da7528760844 Mon Sep 17 00:00:00 2001 From: Joel Wachsler Date: Thu, 14 Jul 2022 11:31:10 +0000 Subject: [PATCH 05/47] Remove dead code --- .devcontainer/Dockerfile | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 57300f3..c641ae1 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -10,11 +10,6 @@ RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ USER vscode -# RUN rustup default nightly \ -# && cargo install cargo-expand \ -# && rustup component add rustfmt \ -# && rustup component add clippy - RUN cargo install cargo-expand \ && rustup component add rustfmt \ && rustup component add clippy From c1cad3daf4bc5ea61f4ed1175c9db752e8c7f466 Mon Sep 17 00:00:00 2001 From: Joel Wachsler Date: Thu, 14 Jul 2022 11:31:42 +0000 Subject: [PATCH 06/47] Format --- qbittorrent-web-api-gen/src/md_parser/token_tree_factory.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/qbittorrent-web-api-gen/src/md_parser/token_tree_factory.rs b/qbittorrent-web-api-gen/src/md_parser/token_tree_factory.rs index f62ebc5..48dcae4 100644 --- a/qbittorrent-web-api-gen/src/md_parser/token_tree_factory.rs +++ b/qbittorrent-web-api-gen/src/md_parser/token_tree_factory.rs @@ -69,7 +69,6 @@ impl TokenTreeFactory { } } - #[cfg(test)] mod tests { use super::*; From 90d3f8a023687bc85c13da8f35f4a6a2fde6af1e Mon Sep 17 00:00:00 2001 From: Joel Wachsler Date: Thu, 14 Jul 2022 12:44:25 +0000 Subject: [PATCH 07/47] Make it easier to write token_tree_factory tests --- Cargo.lock | 47 ++ qbittorrent-web-api-gen/Cargo.toml | 1 + .../src/md_parser/token_tree_factory.rs | 112 ++-- .../token_tree_factory_tests/complex.check | 44 ++ .../token_tree_factory_tests/complex.md | 6 + .../token_tree_factory_tests/log.check | 503 ++++++++++++++++++ .../md_parser/token_tree_factory_tests/log.md | 143 +++++ .../should_remove_surrounding_asterix.check | 17 + .../should_remove_surrounding_asterix.md | 2 + .../should_remove_surrounding_hash.check | 13 + .../should_remove_surrounding_hash.md | 1 + .../single_level.check | 17 + .../token_tree_factory_tests/single_level.md | 2 + 13 files changed, 835 insertions(+), 73 deletions(-) create mode 100644 qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/complex.check create mode 100644 qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/complex.md create mode 100644 qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/log.check create mode 100644 qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/log.md create mode 100644 qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/should_remove_surrounding_asterix.check create mode 100644 qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/should_remove_surrounding_asterix.md create mode 100644 qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/should_remove_surrounding_hash.check create mode 100644 qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/should_remove_surrounding_hash.md create mode 100644 qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/single_level.check create mode 100644 qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/single_level.md diff --git a/Cargo.lock b/Cargo.lock index f5b9100..57613ed 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,6 +11,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "ansi_term" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +dependencies = [ + "winapi", +] + [[package]] name = "anyhow" version = "1.0.58" @@ -81,6 +90,22 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" +[[package]] +name = "ctor" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f877be4f7c9f246b183111634f75baa039715e3f46ce860677d3b19a69fb229c" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "diff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" + [[package]] name = "dissimilar" version = "1.0.4" @@ -487,6 +512,15 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "output_vt100" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66" +dependencies = [ + "winapi", +] + [[package]] name = "parking_lot" version = "0.12.1" @@ -534,6 +568,18 @@ version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" +[[package]] +name = "pretty_assertions" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c89f989ac94207d048d92db058e4f6ec7342b0971fc58d1271ca148b799b3563" +dependencies = [ + "ansi_term", + "ctor", + "diff", + "output_vt100", +] + [[package]] name = "proc-macro2" version = "1.0.40" @@ -561,6 +607,7 @@ version = "0.3.2" dependencies = [ "anyhow", "case", + "pretty_assertions", "proc-macro2", "quote", "regex", diff --git a/qbittorrent-web-api-gen/Cargo.toml b/qbittorrent-web-api-gen/Cargo.toml index eaecf5f..2a6bb56 100644 --- a/qbittorrent-web-api-gen/Cargo.toml +++ b/qbittorrent-web-api-gen/Cargo.toml @@ -32,3 +32,4 @@ trybuild = { version = "1.0.63", features = ["diff"] } anyhow = "1.0.58" tokio = { version = "1.19.2", features = ["full"] } reqwest = { version = "0.11.11", features = ["json", "multipart"] } +pretty_assertions = "1.2.1" diff --git a/qbittorrent-web-api-gen/src/md_parser/token_tree_factory.rs b/qbittorrent-web-api-gen/src/md_parser/token_tree_factory.rs index 48dcae4..9854f8c 100644 --- a/qbittorrent-web-api-gen/src/md_parser/token_tree_factory.rs +++ b/qbittorrent-web-api-gen/src/md_parser/token_tree_factory.rs @@ -73,93 +73,59 @@ impl TokenTreeFactory { mod tests { use super::*; + macro_rules! run_test { + ($test_file:expr) => { + use pretty_assertions::assert_eq; + + // given + let input = include_str!(concat!("token_tree_factory_tests/", $test_file, ".md")); + + // when + let tree = TokenTreeFactory::create(input); + + // then + let tree_as_str = format!("{tree:#?}"); + let should_be = + include_str!(concat!("token_tree_factory_tests/", $test_file, ".check")); + assert_eq!(tree_as_str, should_be); + }; + } + + // use this macro when creating/updating as test + #[allow(unused_macros)] + macro_rules! update_test { + ($test_file:expr) => { + use std::fs; + + let input = include_str!(concat!("token_tree_factory_tests/", $test_file, ".md")); + let tree = TokenTreeFactory::create(input); + let tree_as_str = format!("{tree:#?}"); + fs::write(concat!($test_file, ".check"), tree_as_str).unwrap(); + }; + } + #[test] fn should_remove_surrounding_asterix() { - // given - let input = r#" -# A -**B** - "# - .trim_matches('\n') - .trim(); - - // when - let tree = TokenTreeFactory::create(input); - - // then - println!("{:#?}", tree); - let first = tree.children.first().unwrap(); - let content = first.content.first().unwrap(); - assert_eq!(*content, MdContent::Asterix("B".into())); + run_test!("should_remove_surrounding_asterix"); } #[test] fn should_remove_surrounding_hash() { - // given - let input = r#" -# A # - "# - .trim_matches('\n') - .trim(); - - // when - let tree = TokenTreeFactory::create(input); - - // then - println!("{:#?}", tree); - assert_eq!(tree.children.first().unwrap().title, Some("A".into())); + run_test!("should_remove_surrounding_hash"); } #[test] fn single_level() { - // given - let input = r#" -# A -Foo - "# - .trim_matches('\n') - .trim(); - - // when - let tree = TokenTreeFactory::create(input); - - // then - println!("{:#?}", tree); - assert_eq!(tree.title, None); - let first_child = tree.children.first().unwrap(); - assert_eq!(first_child.title, Some("A".into())); + run_test!("single_level"); } #[test] fn complex() { - // given - let input = r#" -# A -Foo -## B -# C -## D -Bar - "# - .trim_matches('\n') - .trim(); + run_test!("complex"); + } - // when - let tree = TokenTreeFactory::create(input); - - // then - println!("{:#?}", tree); - assert_eq!(tree.title, None); - assert_eq!(tree.children.len(), 2); - - let first = tree.children.get(0).unwrap(); - assert_eq!(first.title, Some("A".into())); - assert_eq!(first.children.len(), 1); - assert_eq!(first.children.first().unwrap().title, Some("B".into())); - - let second = tree.children.get(1).unwrap(); - assert_eq!(second.title, Some("C".into())); - assert_eq!(second.children.len(), 1); - assert_eq!(second.children.first().unwrap().title, Some("D".into())); + #[test] + fn log() { + run_test!("log"); } } diff --git a/qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/complex.check b/qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/complex.check new file mode 100644 index 0000000..16be004 --- /dev/null +++ b/qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/complex.check @@ -0,0 +1,44 @@ +TokenTree { + title: None, + content: [], + children: [ + TokenTree { + title: Some( + "A", + ), + content: [ + Text( + "Foo", + ), + ], + children: [ + TokenTree { + title: Some( + "B", + ), + content: [], + children: [], + }, + ], + }, + TokenTree { + title: Some( + "C", + ), + content: [], + children: [ + TokenTree { + title: Some( + "D", + ), + content: [ + Text( + "Bar", + ), + ], + children: [], + }, + ], + }, + ], +} \ No newline at end of file diff --git a/qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/complex.md b/qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/complex.md new file mode 100644 index 0000000..cfaa8fb --- /dev/null +++ b/qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/complex.md @@ -0,0 +1,6 @@ +# A +Foo +## B +# C +## D +Bar \ No newline at end of file diff --git a/qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/log.check b/qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/log.check new file mode 100644 index 0000000..0e7e5f1 --- /dev/null +++ b/qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/log.check @@ -0,0 +1,503 @@ +TokenTree { + title: None, + content: [], + children: [ + TokenTree { + title: Some( + "Log", + ), + content: [ + Text( + "", + ), + Text( + "All Log API methods are under \"log\", e.g.: `/api/v2/log/methodName`.", + ), + Text( + "", + ), + ], + children: [ + TokenTree { + title: Some( + "Get log", + ), + content: [ + Text( + "", + ), + Text( + "Name: `main`", + ), + Text( + "", + ), + Asterix( + "Parameters:", + ), + Text( + "", + ), + Table( + Table { + header: TableRow { + raw: "Parameter | Type | Description", + columns: [ + "Parameter", + "Type", + "Description", + ], + }, + split: "----------------|---------|------------", + rows: [ + TableRow { + raw: "`normal` | bool | Include normal messages (default: `true`)", + columns: [ + "normal", + "bool", + "Include normal messages (default: true)", + ], + }, + TableRow { + raw: "`info` | bool | Include info messages (default: `true`)", + columns: [ + "info", + "bool", + "Include info messages (default: true)", + ], + }, + TableRow { + raw: "`warning` | bool | Include warning messages (default: `true`)", + columns: [ + "warning", + "bool", + "Include warning messages (default: true)", + ], + }, + TableRow { + raw: "`critical` | bool | Include critical messages (default: `true`)", + columns: [ + "critical", + "bool", + "Include critical messages (default: true)", + ], + }, + TableRow { + raw: "`last_known_id` | integer | Exclude messages with \"message id\" <= `last_known_id` (default: `-1`)", + columns: [ + "last_known_id", + "integer", + "Exclude messages with \"message id\" <= last_known_id (default: -1)", + ], + }, + ], + }, + ), + Text( + "Example:", + ), + Text( + "", + ), + Text( + "```http", + ), + Text( + "/api/v2/log/main?normal=true&info=true&warning=true&critical=true&last_known_id=-1", + ), + Text( + "```", + ), + Text( + "", + ), + Asterix( + "Returns:", + ), + Text( + "", + ), + Table( + Table { + header: TableRow { + raw: "HTTP Status Code | Scenario", + columns: [ + "HTTP Status Code", + "Scenario", + ], + }, + split: "----------------------------------|---------------------", + rows: [ + TableRow { + raw: "200 | All scenarios- see JSON below", + columns: [ + "200", + "All scenarios- see JSON below", + ], + }, + ], + }, + ), + Text( + "The response is a JSON array in which each element is an entry of the log.", + ), + Text( + "", + ), + Text( + "Each element of the array has the following properties:", + ), + Text( + "", + ), + Table( + Table { + header: TableRow { + raw: "Property | Type | Description", + columns: [ + "Property", + "Type", + "Description", + ], + }, + split: "------------|---------|------------", + rows: [ + TableRow { + raw: "`id` | integer | ID of the message", + columns: [ + "id", + "integer", + "ID of the message", + ], + }, + TableRow { + raw: "`message` | string | Text of the message", + columns: [ + "message", + "string", + "Text of the message", + ], + }, + TableRow { + raw: "`timestamp` | integer | Milliseconds since epoch", + columns: [ + "timestamp", + "integer", + "Milliseconds since epoch", + ], + }, + TableRow { + raw: "`type` | integer | Type of the message: Log::NORMAL: `1`, Log::INFO: `2`, Log::WARNING: `4`, Log::CRITICAL: `8`", + columns: [ + "type", + "integer", + "Type of the message: Log::NORMAL: 1, Log::INFO: 2, Log::WARNING: 4, Log::CRITICAL: 8", + ], + }, + ], + }, + ), + Text( + "Example:", + ), + Text( + "", + ), + Text( + "```JSON", + ), + Text( + "[", + ), + Text( + " {", + ), + Text( + " \"id\":0,", + ), + Text( + " \"message\":\"qBittorrent v3.4.0 started\",", + ), + Text( + " \"timestamp\":1507969127860,", + ), + Text( + " \"type\":1", + ), + Text( + " },", + ), + Text( + " {", + ), + Text( + " \"id\":1,", + ), + Text( + " \"message\":\"qBittorrent is trying to listen on any interface port: 19036\",", + ), + Text( + " \"timestamp\":1507969127869,", + ), + Text( + " \"type\":2", + ), + Text( + " },", + ), + Text( + " {", + ), + Text( + " \"id\":2,", + ), + Text( + " \"message\":\"Peer ID: -qB3400-\",", + ), + Text( + " \"timestamp\":1507969127870,", + ), + Text( + " \"type\":1", + ), + Text( + " },", + ), + Text( + " {", + ), + Text( + " \"id\":3,", + ), + Text( + " \"message\":\"HTTP User-Agent is 'qBittorrent/3.4.0'\",", + ), + Text( + " \"timestamp\":1507969127870,", + ), + Text( + " \"type\":1", + ), + Text( + " },", + ), + Text( + " {", + ), + Text( + " \"id\":4,", + ), + Text( + " \"message\":\"DHT support [ON]\",", + ), + Text( + " \"timestamp\":1507969127871,", + ), + Text( + " \"type\":2", + ), + Text( + " },", + ), + Text( + " {", + ), + Text( + " \"id\":5,", + ), + Text( + " \"message\":\"Local Peer Discovery support [ON]\",", + ), + Text( + " \"timestamp\":1507969127871,", + ), + Text( + " \"type\":2", + ), + Text( + " },", + ), + Text( + " {", + ), + Text( + " \"id\":6,", + ), + Text( + " \"message\":\"PeX support [ON]\",", + ), + Text( + " \"timestamp\":1507969127871,", + ), + Text( + " \"type\":2", + ), + Text( + " },", + ), + Text( + " {", + ), + Text( + " \"id\":7,", + ), + Text( + " \"message\":\"Anonymous mode [OFF]\",", + ), + Text( + " \"timestamp\":1507969127871,", + ), + Text( + " \"type\":2", + ), + Text( + " },", + ), + Text( + " {", + ), + Text( + " \"id\":8,", + ), + Text( + " \"message\":\"Encryption support [ON]\",", + ), + Text( + " \"timestamp\":1507969127871,", + ), + Text( + " \"type\":2", + ), + Text( + " },", + ), + Text( + " {", + ), + Text( + " \"id\":9,", + ), + Text( + " \"message\":\"Embedded Tracker [OFF]\",", + ), + Text( + " \"timestamp\":1507969127871,", + ), + Text( + " \"type\":2", + ), + Text( + " },", + ), + Text( + " {", + ), + Text( + " \"id\":10,", + ), + Text( + " \"message\":\"UPnP / NAT-PMP support [ON]\",", + ), + Text( + " \"timestamp\":1507969127873,", + ), + Text( + " \"type\":2", + ), + Text( + " },", + ), + Text( + " {", + ), + Text( + " \"id\":11,", + ), + Text( + " \"message\":\"Web UI: Now listening on port 8080\",", + ), + Text( + " \"timestamp\":1507969127883,", + ), + Text( + " \"type\":1", + ), + Text( + " },", + ), + Text( + " {", + ), + Text( + " \"id\":12,", + ), + Text( + " \"message\":\"Options were saved successfully.\",", + ), + Text( + " \"timestamp\":1507969128055,", + ), + Text( + " \"type\":1", + ), + Text( + " },", + ), + Text( + " {", + ), + Text( + " \"id\":13,", + ), + Text( + " \"message\":\"qBittorrent is successfully listening on interface :: port: TCP/19036\",", + ), + Text( + " \"timestamp\":1507969128270,", + ), + Text( + " \"type\":2", + ), + Text( + " },", + ), + Text( + " {", + ), + Text( + " \"id\":14,", + ), + Text( + " \"message\":\"qBittorrent is successfully listening on interface 0.0.0.0 port: TCP/19036\",", + ), + Text( + " \"timestamp\":1507969128271,", + ), + Text( + " \"type\":2", + ), + Text( + " },", + ), + Text( + " {", + ), + Text( + " \"id\":15,", + ), + Text( + " \"message\":\"qBittorrent is successfully listening on interface 0.0.0.0 port: UDP/19036\",", + ), + Text( + " \"timestamp\":1507969128272,", + ), + Text( + " \"type\":2", + ), + ], + children: [], + }, + ], + }, + ], +} \ No newline at end of file diff --git a/qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/log.md b/qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/log.md new file mode 100644 index 0000000..52df39e --- /dev/null +++ b/qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/log.md @@ -0,0 +1,143 @@ +# Log # + +All Log API methods are under "log", e.g.: `/api/v2/log/methodName`. + +## Get log ## + +Name: `main` + +**Parameters:** + +Parameter | Type | Description +----------------|---------|------------ +`normal` | bool | Include normal messages (default: `true`) +`info` | bool | Include info messages (default: `true`) +`warning` | bool | Include warning messages (default: `true`) +`critical` | bool | Include critical messages (default: `true`) +`last_known_id` | integer | Exclude messages with "message id" <= `last_known_id` (default: `-1`) + +Example: + +```http +/api/v2/log/main?normal=true&info=true&warning=true&critical=true&last_known_id=-1 +``` + +**Returns:** + +HTTP Status Code | Scenario +----------------------------------|--------------------- +200 | All scenarios- see JSON below + +The response is a JSON array in which each element is an entry of the log. + +Each element of the array has the following properties: + +Property | Type | Description +------------|---------|------------ +`id` | integer | ID of the message +`message` | string | Text of the message +`timestamp` | integer | Milliseconds since epoch +`type` | integer | Type of the message: Log::NORMAL: `1`, Log::INFO: `2`, Log::WARNING: `4`, Log::CRITICAL: `8` + +Example: + +```JSON +[ + { + "id":0, + "message":"qBittorrent v3.4.0 started", + "timestamp":1507969127860, + "type":1 + }, + { + "id":1, + "message":"qBittorrent is trying to listen on any interface port: 19036", + "timestamp":1507969127869, + "type":2 + }, + { + "id":2, + "message":"Peer ID: -qB3400-", + "timestamp":1507969127870, + "type":1 + }, + { + "id":3, + "message":"HTTP User-Agent is 'qBittorrent/3.4.0'", + "timestamp":1507969127870, + "type":1 + }, + { + "id":4, + "message":"DHT support [ON]", + "timestamp":1507969127871, + "type":2 + }, + { + "id":5, + "message":"Local Peer Discovery support [ON]", + "timestamp":1507969127871, + "type":2 + }, + { + "id":6, + "message":"PeX support [ON]", + "timestamp":1507969127871, + "type":2 + }, + { + "id":7, + "message":"Anonymous mode [OFF]", + "timestamp":1507969127871, + "type":2 + }, + { + "id":8, + "message":"Encryption support [ON]", + "timestamp":1507969127871, + "type":2 + }, + { + "id":9, + "message":"Embedded Tracker [OFF]", + "timestamp":1507969127871, + "type":2 + }, + { + "id":10, + "message":"UPnP / NAT-PMP support [ON]", + "timestamp":1507969127873, + "type":2 + }, + { + "id":11, + "message":"Web UI: Now listening on port 8080", + "timestamp":1507969127883, + "type":1 + }, + { + "id":12, + "message":"Options were saved successfully.", + "timestamp":1507969128055, + "type":1 + }, + { + "id":13, + "message":"qBittorrent is successfully listening on interface :: port: TCP/19036", + "timestamp":1507969128270, + "type":2 + }, + { + "id":14, + "message":"qBittorrent is successfully listening on interface 0.0.0.0 port: TCP/19036", + "timestamp":1507969128271, + "type":2 + }, + { + "id":15, + "message":"qBittorrent is successfully listening on interface 0.0.0.0 port: UDP/19036", + "timestamp":1507969128272, + "type":2 + } +] +``` diff --git a/qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/should_remove_surrounding_asterix.check b/qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/should_remove_surrounding_asterix.check new file mode 100644 index 0000000..2c66917 --- /dev/null +++ b/qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/should_remove_surrounding_asterix.check @@ -0,0 +1,17 @@ +TokenTree { + title: None, + content: [], + children: [ + TokenTree { + title: Some( + "A", + ), + content: [ + Asterix( + "B", + ), + ], + children: [], + }, + ], +} \ No newline at end of file diff --git a/qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/should_remove_surrounding_asterix.md b/qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/should_remove_surrounding_asterix.md new file mode 100644 index 0000000..318a664 --- /dev/null +++ b/qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/should_remove_surrounding_asterix.md @@ -0,0 +1,2 @@ +# A +**B** \ No newline at end of file diff --git a/qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/should_remove_surrounding_hash.check b/qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/should_remove_surrounding_hash.check new file mode 100644 index 0000000..bb00231 --- /dev/null +++ b/qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/should_remove_surrounding_hash.check @@ -0,0 +1,13 @@ +TokenTree { + title: None, + content: [], + children: [ + TokenTree { + title: Some( + "A", + ), + content: [], + children: [], + }, + ], +} \ No newline at end of file diff --git a/qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/should_remove_surrounding_hash.md b/qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/should_remove_surrounding_hash.md new file mode 100644 index 0000000..c3fd722 --- /dev/null +++ b/qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/should_remove_surrounding_hash.md @@ -0,0 +1 @@ +# A # \ No newline at end of file diff --git a/qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/single_level.check b/qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/single_level.check new file mode 100644 index 0000000..34e9f2c --- /dev/null +++ b/qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/single_level.check @@ -0,0 +1,17 @@ +TokenTree { + title: None, + content: [], + children: [ + TokenTree { + title: Some( + "A", + ), + content: [ + Text( + "Foo", + ), + ], + children: [], + }, + ], +} \ No newline at end of file diff --git a/qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/single_level.md b/qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/single_level.md new file mode 100644 index 0000000..f5e1cf8 --- /dev/null +++ b/qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/single_level.md @@ -0,0 +1,2 @@ +# A +Foo \ No newline at end of file From 391ed560a6df1830f37a9d75db982530520f8999 Mon Sep 17 00:00:00 2001 From: Joel Wachsler Date: Thu, 14 Jul 2022 12:46:11 +0000 Subject: [PATCH 08/47] Do not package tests --- qbittorrent-web-api-gen/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qbittorrent-web-api-gen/Cargo.toml b/qbittorrent-web-api-gen/Cargo.toml index 2a6bb56..181d229 100644 --- a/qbittorrent-web-api-gen/Cargo.toml +++ b/qbittorrent-web-api-gen/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT" keywords = ["qbittorrent"] repository = "https://github.com/JoelWachsler/qbittorrent-web-api" description = "Generated web api for qBittorrent" -exclude = ["*.txt", "tests"] +exclude = ["*.txt", "tests", "qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests"] # we use trybuild instead autotests = false From f1c3656e6e079a1d4c268bfaa4e98fe8242bd7eb Mon Sep 17 00:00:00 2001 From: Joel Wachsler Date: Thu, 14 Jul 2022 13:00:39 +0000 Subject: [PATCH 09/47] Fix table parsing --- .../src/md_parser/md_token.rs | 25 ++++-- .../src/md_parser/token_tree_factory.rs | 15 +++- .../token_tree_factory_tests/log.check | 18 ++++ .../multi_table.check | 86 +++++++++++++++++++ .../token_tree_factory_tests/multi_table.md | 12 +++ 5 files changed, 149 insertions(+), 7 deletions(-) create mode 100644 qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/multi_table.check create mode 100644 qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/multi_table.md diff --git a/qbittorrent-web-api-gen/src/md_parser/md_token.rs b/qbittorrent-web-api-gen/src/md_parser/md_token.rs index 439216e..39de178 100644 --- a/qbittorrent-web-api-gen/src/md_parser/md_token.rs +++ b/qbittorrent-web-api-gen/src/md_parser/md_token.rs @@ -77,10 +77,21 @@ impl MdToken { } pub fn from(content: &str) -> Vec { + // to prevent infinite loops + let mut max_iterations = 10000; + let mut decreate_max_iterations = || { + max_iterations -= 1; + if max_iterations <= 0 { + panic!("Max iterations reached, missing termination?"); + }; + }; + let mut output = Vec::new(); - let mut iter = content.lines(); + let mut iter = content.lines().peekable(); while let Some(line) = iter.next() { + decreate_max_iterations(); + // assume this is a table if line.contains('|') { let to_columns = |column_line: &str| { @@ -97,16 +108,18 @@ impl MdToken { }; let table_split = iter.next().unwrap(); let mut table_rows = Vec::new(); - while let Some(row_line) = iter.next() { - if !row_line.contains('|') { + while let Some(peeked_row_line) = iter.peek() { + decreate_max_iterations(); + + if !peeked_row_line.contains('|') { // we've reached the end of the table, let's go back one step - iter.next_back(); break; } + let next_row_line = iter.next().unwrap(); let table_row = TableRow { - raw: row_line.into(), - columns: to_columns(row_line), + raw: next_row_line.to_string(), + columns: to_columns(next_row_line), }; table_rows.push(table_row); diff --git a/qbittorrent-web-api-gen/src/md_parser/token_tree_factory.rs b/qbittorrent-web-api-gen/src/md_parser/token_tree_factory.rs index 9854f8c..d04ac8b 100644 --- a/qbittorrent-web-api-gen/src/md_parser/token_tree_factory.rs +++ b/qbittorrent-web-api-gen/src/md_parser/token_tree_factory.rs @@ -96,11 +96,19 @@ mod tests { macro_rules! update_test { ($test_file:expr) => { use std::fs; + use std::path::Path; let input = include_str!(concat!("token_tree_factory_tests/", $test_file, ".md")); let tree = TokenTreeFactory::create(input); let tree_as_str = format!("{tree:#?}"); - fs::write(concat!($test_file, ".check"), tree_as_str).unwrap(); + let file = concat!("src/md_parser/token_tree_factory_tests/", $test_file, ".check"); + + // prevent user from accidentially leaving the current macro in a test + if Path::new(file).exists() { + panic!("Test case already exists: {file}"); + } + + fs::write(file, tree_as_str).unwrap(); }; } @@ -128,4 +136,9 @@ mod tests { fn log() { run_test!("log"); } + + #[test] + fn multi_table() { + run_test!("multi_table"); + } } diff --git a/qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/log.check b/qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/log.check index 0e7e5f1..e19fe27 100644 --- a/qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/log.check +++ b/qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/log.check @@ -93,6 +93,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "Example:", ), @@ -138,6 +141,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "The response is a JSON array in which each element is an entry of the log.", ), @@ -197,6 +203,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "Example:", ), @@ -494,6 +503,15 @@ TokenTree { Text( " \"type\":2", ), + Text( + " }", + ), + Text( + "]", + ), + Text( + "```", + ), ], children: [], }, diff --git a/qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/multi_table.check b/qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/multi_table.check new file mode 100644 index 0000000..7efc49d --- /dev/null +++ b/qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/multi_table.check @@ -0,0 +1,86 @@ +TokenTree { + title: None, + content: [], + children: [ + TokenTree { + title: Some( + "Foo", + ), + content: [ + Text( + "", + ), + ], + children: [ + TokenTree { + title: Some( + "Bar", + ), + content: [ + Table( + Table { + header: TableRow { + raw: "Parameter | Type | Description", + columns: [ + "Parameter", + "Type", + "Description", + ], + }, + split: "----------------|---------|------------", + rows: [ + TableRow { + raw: "`normal` | bool | Include normal messages (default: `true`)", + columns: [ + "normal", + "bool", + "Include normal messages (default: true)", + ], + }, + ], + }, + ), + Text( + "", + ), + ], + children: [], + }, + TokenTree { + title: Some( + "Baz", + ), + content: [ + Table( + Table { + header: TableRow { + raw: "Parameter | Type | Description", + columns: [ + "Parameter", + "Type", + "Description", + ], + }, + split: "----------------|---------|------------", + rows: [ + TableRow { + raw: "`last_known_id` | integer | Exclude messages with \"message id\" <= `last_known_id` (default: `-1`)", + columns: [ + "last_known_id", + "integer", + "Exclude messages with \"message id\" <= last_known_id (default: -1)", + ], + }, + ], + }, + ), + Text( + "", + ), + ], + children: [], + }, + ], + }, + ], +} \ No newline at end of file diff --git a/qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/multi_table.md b/qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/multi_table.md new file mode 100644 index 0000000..c5a3510 --- /dev/null +++ b/qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/multi_table.md @@ -0,0 +1,12 @@ +# Foo + +## Bar +Parameter | Type | Description +----------------|---------|------------ +`normal` | bool | Include normal messages (default: `true`) + +## Baz +Parameter | Type | Description +----------------|---------|------------ +`last_known_id` | integer | Exclude messages with "message id" <= `last_known_id` (default: `-1`) + From 4a0db615a57a6f6dffbcfc0c5019833fa75a3b49 Mon Sep 17 00:00:00 2001 From: Joel Wachsler Date: Thu, 14 Jul 2022 13:07:50 +0000 Subject: [PATCH 10/47] Add search tests --- qbittorrent-web-api-gen/groups.txt | 323 +++- qbittorrent-web-api-gen/tests/search_types.rs | 20 + qbittorrent-web-api-gen/tests/tests.rs | 2 +- qbittorrent-web-api-gen/token_tree.txt | 1410 ++++++++++++++++- 4 files changed, 1728 insertions(+), 27 deletions(-) create mode 100644 qbittorrent-web-api-gen/tests/search_types.rs diff --git a/qbittorrent-web-api-gen/groups.txt b/qbittorrent-web-api-gen/groups.txt index 96d8e85..2d6c67a 100644 --- a/qbittorrent-web-api-gen/groups.txt +++ b/qbittorrent-web-api-gen/groups.txt @@ -5,7 +5,7 @@ ApiMethod { name: "login", description: Some( - "Example showing how to login and execute a command that requires authentication using `curl`:\n\n```sh\n$ curl -i --header 'Referer: http://localhost:8080' --data 'username=admin&password=adminadmin' http://localhost:8080/api/v2/auth/login\nHTTP/1.1 200 OK\nContent-Encoding:\nContent-Length: 3\nContent-Type: text/plain; charset=UTF-8\nSet-Cookie: SID=hBc7TxF76ERhvIw0jQQ4LZ7Z1jQUV0tQ; path=/\n$ curl http://localhost:8080/api/v2/torrents/info --cookie \"SID=hBc7TxF76ERhvIw0jQQ4LZ7Z1jQUV0tQ\"\n```\n\nNote: Set `Referer` or `Origin` header to the exact same domain and port as used in the HTTP query `Host` header.", + "Upon success, the response will contain a cookie with your SID. You must supply the cookie whenever you want to perform an operation that requires authentication.\n\nExample showing how to login and execute a command that requires authentication using `curl`:\n\n```sh\n$ curl -i --header 'Referer: http://localhost:8080' --data 'username=admin&password=adminadmin' http://localhost:8080/api/v2/auth/login\nHTTP/1.1 200 OK\nContent-Encoding:\nContent-Length: 3\nContent-Type: text/plain; charset=UTF-8\nSet-Cookie: SID=hBc7TxF76ERhvIw0jQQ4LZ7Z1jQUV0tQ; path=/\n$ curl http://localhost:8080/api/v2/torrents/info --cookie \"SID=hBc7TxF76ERhvIw0jQQ4LZ7Z1jQUV0tQ\"\n```\n\nNote: Set `Referer` or `Origin` header to the exact same domain and port as used in the HTTP query `Host` header.", ), parameters: Some( [ @@ -54,21 +54,27 @@ methods: [ ApiMethod { name: "version", - description: None, + description: Some( + "The response is a string with the application version, e.g. `v4.1.3`", + ), parameters: None, return_type: None, url: "version", }, ApiMethod { name: "webapiVersion", - description: None, + description: Some( + "The response is a string with the WebAPI version, e.g. `2.0`", + ), parameters: None, return_type: None, url: "webapiVersion", }, ApiMethod { name: "buildInfo", - description: None, + description: Some( + "The response is a JSON object containing the following fields", + ), parameters: None, return_type: Some( ReturnType { @@ -164,7 +170,7 @@ ApiMethod { name: "preferences", description: Some( - "Possible fields:\n\nPossible values of `scan_dirs`:\n\nPossible values of `scheduler_days`:\n\nPossible values of `encryption`:\n\nNB: the first options allows you to use both encrypted and unencrypted connections (this is the default); other options are mutually exclusive: e.g. by forcing encryption on you won't be able to use unencrypted connections and vice versa.\n\nPossible values of `proxy_type`:\n\nPossible values of `dyndns_service`:\n\nPossible values of `max_ratio_act`:\n\nPossible values of `bittorrent_protocol`:\n\nPossible values of `upload_choking_algorithm`:\n\nPossible values of `upload_slots_behavior`:\n\nPossible values of `utp_tcp_mixed_mode`:\n\nExample:\n\n```JSON\n{\n \"add_trackers\": \"\",\n \"add_trackers_enabled\": false,\n \"alt_dl_limit\": 10240,\n \"alt_up_limit\": 10240,\n \"alternative_webui_enabled\": false,\n \"alternative_webui_path\": \"/home/user/Documents/qbit-webui\",\n \"announce_ip\": \"\",\n \"announce_to_all_tiers\": true,\n \"announce_to_all_trackers\": false,\n \"anonymous_mode\": false,\n \"async_io_threads\": 4,\n \"auto_delete_mode\": 0,\n \"auto_tmm_enabled\": false,\n \"autorun_enabled\": false,\n \"autorun_program\": \"\",\n \"banned_IPs\": \"\",\n \"bittorrent_protocol\": 0,\n \"bypass_auth_subnet_whitelist\": \"\",\n \"bypass_auth_subnet_whitelist_enabled\": false,\n \"bypass_local_auth\": false,\n \"category_changed_tmm_enabled\": false,\n \"checking_memory_use\": 32,\n \"create_subfolder_enabled\": true,\n \"current_interface_address\": \"\",\n \"current_network_interface\": \"\",\n \"dht\": true,\n \"disk_cache\": -1,\n \"disk_cache_ttl\": 60,\n \"dl_limit\": 0,\n \"dont_count_slow_torrents\": false,\n \"dyndns_domain\": \"changeme.dyndns.org\",\n \"dyndns_enabled\": false,\n \"dyndns_password\": \"\",\n \"dyndns_service\": 0,\n \"dyndns_username\": \"\",\n \"embedded_tracker_port\": 9000,\n \"enable_coalesce_read_write\": false,\n \"enable_embedded_tracker\": false,\n \"enable_multi_connections_from_same_ip\": false,\n \"enable_os_cache\": true,\n \"enable_piece_extent_affinity\": false,\n \"enable_upload_suggestions\": false,\n \"encryption\": 0,\n \"export_dir\": \"/home/user/Downloads/all\",\n \"export_dir_fin\": \"/home/user/Downloads/completed\",\n \"file_pool_size\": 40,\n \"incomplete_files_ext\": false,\n \"ip_filter_enabled\": false,\n \"ip_filter_path\": \"\",\n \"ip_filter_trackers\": false,\n \"limit_lan_peers\": true,\n \"limit_tcp_overhead\": false,\n \"limit_utp_rate\": true,\n \"listen_port\": 58925,\n \"locale\": \"en\",\n \"lsd\": true,\n \"mail_notification_auth_enabled\": false,\n \"mail_notification_email\": \"\",\n \"mail_notification_enabled\": false,\n \"mail_notification_password\": \"\",\n \"mail_notification_sender\": \"qBittorrent_notification@example.com\",\n \"mail_notification_smtp\": \"smtp.changeme.com\",\n \"mail_notification_ssl_enabled\": false,\n \"mail_notification_username\": \"\",\n \"max_active_downloads\": 3,\n \"max_active_torrents\": 5,\n \"max_active_uploads\": 3,\n \"max_connec\": 500,\n \"max_connec_per_torrent\": 100,\n \"max_ratio\": -1,\n \"max_ratio_act\": 0,\n \"max_ratio_enabled\": false,\n \"max_seeding_time\": -1,\n \"max_seeding_time_enabled\": false,\n \"max_uploads\": -1,\n \"max_uploads_per_torrent\": -1,\n \"outgoing_ports_max\": 0,\n \"outgoing_ports_min\": 0,\n \"pex\": true,\n \"preallocate_all\": false,\n \"proxy_auth_enabled\": false,\n \"proxy_ip\": \"0.0.0.0\",\n \"proxy_password\": \"\",\n \"proxy_peer_connections\": false,\n \"proxy_port\": 8080,\n \"proxy_torrents_only\": false,\n \"proxy_type\": 0,\n \"proxy_username\": \"\",\n \"queueing_enabled\": false,\n \"random_port\": false,\n \"recheck_completed_torrents\": false,\n \"resolve_peer_countries\": true,\n \"rss_auto_downloading_enabled\":true,\n \"rss_download_repack_proper_episodes\":true,\n \"rss_max_articles_per_feed\":50,\n \"rss_processing_enabled\":true,\n \"rss_refresh_interval\":30,\n \"rss_smart_episode_filters\":\"s(\\\\d+)e(\\\\d+)\\n(\\\\d+)x(\\\\d+)\\n(\\\\d{4}[.\\\\-]\\\\d{1,2}[.\\\\-]\\\\d{1,2})\",\n \"save_path\": \"/home/user/Downloads/\",\n \"save_path_changed_tmm_enabled\": false,\n \"save_resume_data_interval\": 60,\n \"scan_dirs\":\n {\n \"/home/user/Downloads/incoming/games\": 0,\n \"/home/user/Downloads/incoming/movies\": 1,\n },\n \"schedule_from_hour\": 8,\n \"schedule_from_min\": 0,\n \"schedule_to_hour\": 20,\n \"schedule_to_min\": 0,\n \"scheduler_days\": 0,\n \"scheduler_enabled\": false,\n \"send_buffer_low_watermark\": 10,\n \"send_buffer_watermark\": 500,\n \"send_buffer_watermark_factor\": 50,\n \"slow_torrent_dl_rate_threshold\": 2,\n \"slow_torrent_inactive_timer\": 60,\n \"slow_torrent_ul_rate_threshold\": 2,\n \"socket_backlog_size\": 30,\n \"start_paused_enabled\": false,\n \"stop_tracker_timeout\": 1,\n \"temp_path\": \"/home/user/Downloads/temp\",\n \"temp_path_enabled\": false,\n \"torrent_changed_tmm_enabled\": true,\n \"up_limit\": 0,\n \"upload_choking_algorithm\": 1,\n \"upload_slots_behavior\": 0,\n \"upnp\": true,\n \"use_https\": false,\n \"utp_tcp_mixed_mode\": 0,\n \"web_ui_address\": \"*\",\n \"web_ui_ban_duration\": 3600,\n \"web_ui_clickjacking_protection_enabled\": true,\n \"web_ui_csrf_protection_enabled\": true,\n \"web_ui_custom_http_headers\": \"\",\n \"web_ui_domain_list\": \"*\",\n \"web_ui_host_header_validation_enabled\": true,\n \"web_ui_https_cert_path\": \"\",\n \"web_ui_https_key_path\": \"\",\n \"web_ui_max_auth_fail_count\": 5,\n \"web_ui_port\": 8080,\n \"web_ui_secure_cookie_enabled\": true,\n \"web_ui_session_timeout\": 3600,\n \"web_ui_upnp\": false,\n \"web_ui_use_custom_http_headers_enabled\": false,\n \"web_ui_username\": \"admin\"\n}\n```", + "The response is a JSON object with several fields (key-value) pairs representing the application's settings. The contents may vary depending on which settings are present in qBittorrent.ini.\n\nPossible fields:\n\n\nPossible values of `scan_dirs`:\n\n\nPossible values of `scheduler_days`:\n\n\nPossible values of `encryption`:\n\n\nNB: the first options allows you to use both encrypted and unencrypted connections (this is the default); other options are mutually exclusive: e.g. by forcing encryption on you won't be able to use unencrypted connections and vice versa.\n\nPossible values of `proxy_type`:\n\n\nPossible values of `dyndns_service`:\n\n\nPossible values of `max_ratio_act`:\n\n\nPossible values of `bittorrent_protocol`:\n\n\nPossible values of `upload_choking_algorithm`:\n\n\nPossible values of `upload_slots_behavior`:\n\n\nPossible values of `utp_tcp_mixed_mode`:\n\n\nExample:\n\n```JSON\n{\n \"add_trackers\": \"\",\n \"add_trackers_enabled\": false,\n \"alt_dl_limit\": 10240,\n \"alt_up_limit\": 10240,\n \"alternative_webui_enabled\": false,\n \"alternative_webui_path\": \"/home/user/Documents/qbit-webui\",\n \"announce_ip\": \"\",\n \"announce_to_all_tiers\": true,\n \"announce_to_all_trackers\": false,\n \"anonymous_mode\": false,\n \"async_io_threads\": 4,\n \"auto_delete_mode\": 0,\n \"auto_tmm_enabled\": false,\n \"autorun_enabled\": false,\n \"autorun_program\": \"\",\n \"banned_IPs\": \"\",\n \"bittorrent_protocol\": 0,\n \"bypass_auth_subnet_whitelist\": \"\",\n \"bypass_auth_subnet_whitelist_enabled\": false,\n \"bypass_local_auth\": false,\n \"category_changed_tmm_enabled\": false,\n \"checking_memory_use\": 32,\n \"create_subfolder_enabled\": true,\n \"current_interface_address\": \"\",\n \"current_network_interface\": \"\",\n \"dht\": true,\n \"disk_cache\": -1,\n \"disk_cache_ttl\": 60,\n \"dl_limit\": 0,\n \"dont_count_slow_torrents\": false,\n \"dyndns_domain\": \"changeme.dyndns.org\",\n \"dyndns_enabled\": false,\n \"dyndns_password\": \"\",\n \"dyndns_service\": 0,\n \"dyndns_username\": \"\",\n \"embedded_tracker_port\": 9000,\n \"enable_coalesce_read_write\": false,\n \"enable_embedded_tracker\": false,\n \"enable_multi_connections_from_same_ip\": false,\n \"enable_os_cache\": true,\n \"enable_piece_extent_affinity\": false,\n \"enable_upload_suggestions\": false,\n \"encryption\": 0,\n \"export_dir\": \"/home/user/Downloads/all\",\n \"export_dir_fin\": \"/home/user/Downloads/completed\",\n \"file_pool_size\": 40,\n \"incomplete_files_ext\": false,\n \"ip_filter_enabled\": false,\n \"ip_filter_path\": \"\",\n \"ip_filter_trackers\": false,\n \"limit_lan_peers\": true,\n \"limit_tcp_overhead\": false,\n \"limit_utp_rate\": true,\n \"listen_port\": 58925,\n \"locale\": \"en\",\n \"lsd\": true,\n \"mail_notification_auth_enabled\": false,\n \"mail_notification_email\": \"\",\n \"mail_notification_enabled\": false,\n \"mail_notification_password\": \"\",\n \"mail_notification_sender\": \"qBittorrent_notification@example.com\",\n \"mail_notification_smtp\": \"smtp.changeme.com\",\n \"mail_notification_ssl_enabled\": false,\n \"mail_notification_username\": \"\",\n \"max_active_downloads\": 3,\n \"max_active_torrents\": 5,\n \"max_active_uploads\": 3,\n \"max_connec\": 500,\n \"max_connec_per_torrent\": 100,\n \"max_ratio\": -1,\n \"max_ratio_act\": 0,\n \"max_ratio_enabled\": false,\n \"max_seeding_time\": -1,\n \"max_seeding_time_enabled\": false,\n \"max_uploads\": -1,\n \"max_uploads_per_torrent\": -1,\n \"outgoing_ports_max\": 0,\n \"outgoing_ports_min\": 0,\n \"pex\": true,\n \"preallocate_all\": false,\n \"proxy_auth_enabled\": false,\n \"proxy_ip\": \"0.0.0.0\",\n \"proxy_password\": \"\",\n \"proxy_peer_connections\": false,\n \"proxy_port\": 8080,\n \"proxy_torrents_only\": false,\n \"proxy_type\": 0,\n \"proxy_username\": \"\",\n \"queueing_enabled\": false,\n \"random_port\": false,\n \"recheck_completed_torrents\": false,\n \"resolve_peer_countries\": true,\n \"rss_auto_downloading_enabled\":true,\n \"rss_download_repack_proper_episodes\":true,\n \"rss_max_articles_per_feed\":50,\n \"rss_processing_enabled\":true,\n \"rss_refresh_interval\":30,\n \"rss_smart_episode_filters\":\"s(\\\\d+)e(\\\\d+)\\n(\\\\d+)x(\\\\d+)\\n(\\\\d{4}[.\\\\-]\\\\d{1,2}[.\\\\-]\\\\d{1,2})\",\n \"save_path\": \"/home/user/Downloads/\",\n \"save_path_changed_tmm_enabled\": false,\n \"save_resume_data_interval\": 60,\n \"scan_dirs\":\n {\n \"/home/user/Downloads/incoming/games\": 0,\n \"/home/user/Downloads/incoming/movies\": 1,\n },\n \"schedule_from_hour\": 8,\n \"schedule_from_min\": 0,\n \"schedule_to_hour\": 20,\n \"schedule_to_min\": 0,\n \"scheduler_days\": 0,\n \"scheduler_enabled\": false,\n \"send_buffer_low_watermark\": 10,\n \"send_buffer_watermark\": 500,\n \"send_buffer_watermark_factor\": 50,\n \"slow_torrent_dl_rate_threshold\": 2,\n \"slow_torrent_inactive_timer\": 60,\n \"slow_torrent_ul_rate_threshold\": 2,\n \"socket_backlog_size\": 30,\n \"start_paused_enabled\": false,\n \"stop_tracker_timeout\": 1,\n \"temp_path\": \"/home/user/Downloads/temp\",\n \"temp_path_enabled\": false,\n \"torrent_changed_tmm_enabled\": true,\n \"up_limit\": 0,\n \"upload_choking_algorithm\": 1,\n \"upload_slots_behavior\": 0,\n \"upnp\": true,\n \"use_https\": false,\n \"utp_tcp_mixed_mode\": 0,\n \"web_ui_address\": \"*\",\n \"web_ui_ban_duration\": 3600,\n \"web_ui_clickjacking_protection_enabled\": true,\n \"web_ui_csrf_protection_enabled\": true,\n \"web_ui_custom_http_headers\": \"\",\n \"web_ui_domain_list\": \"*\",\n \"web_ui_host_header_validation_enabled\": true,\n \"web_ui_https_cert_path\": \"\",\n \"web_ui_https_key_path\": \"\",\n \"web_ui_max_auth_fail_count\": 5,\n \"web_ui_port\": 8080,\n \"web_ui_secure_cookie_enabled\": true,\n \"web_ui_session_timeout\": 3600,\n \"web_ui_upnp\": false,\n \"web_ui_use_custom_http_headers_enabled\": false,\n \"web_ui_username\": \"admin\"\n}\n```", ), parameters: None, return_type: Some( @@ -2571,7 +2577,9 @@ }, ApiMethod { name: "defaultSavePath", - description: None, + description: Some( + "The response is a string with the default save path, e.g. `C:/Users/Dayman/Downloads`.", + ), parameters: None, return_type: None, url: "defaultSavePath", @@ -2588,7 +2596,7 @@ ApiMethod { name: "main", description: Some( - "Each element of the array has the following properties:\n\nExample:\n\n```JSON\n[\n {\n \"id\":0,\n \"message\":\"qBittorrent v3.4.0 started\",\n \"timestamp\":1507969127860,\n \"type\":1\n },\n {\n \"id\":1,\n \"message\":\"qBittorrent is trying to listen on any interface port: 19036\",\n \"timestamp\":1507969127869,\n \"type\":2\n },\n {\n \"id\":2,\n \"message\":\"Peer ID: -qB3400-\",\n \"timestamp\":1507969127870,\n \"type\":1\n },\n {\n \"id\":3,\n \"message\":\"HTTP User-Agent is 'qBittorrent/3.4.0'\",\n \"timestamp\":1507969127870,\n \"type\":1\n },\n {\n \"id\":4,\n \"message\":\"DHT support [ON]\",\n \"timestamp\":1507969127871,\n \"type\":2\n },\n {\n \"id\":5,\n \"message\":\"Local Peer Discovery support [ON]\",\n \"timestamp\":1507969127871,\n \"type\":2\n },\n {\n \"id\":6,\n \"message\":\"PeX support [ON]\",\n \"timestamp\":1507969127871,\n \"type\":2\n },\n {\n \"id\":7,\n \"message\":\"Anonymous mode [OFF]\",\n \"timestamp\":1507969127871,\n \"type\":2\n },\n {\n \"id\":8,\n \"message\":\"Encryption support [ON]\",\n \"timestamp\":1507969127871,\n \"type\":2\n },\n {\n \"id\":9,\n \"message\":\"Embedded Tracker [OFF]\",\n \"timestamp\":1507969127871,\n \"type\":2\n },\n {\n \"id\":10,\n \"message\":\"UPnP / NAT-PMP support [ON]\",\n \"timestamp\":1507969127873,\n \"type\":2\n },\n {\n \"id\":11,\n \"message\":\"Web UI: Now listening on port 8080\",\n \"timestamp\":1507969127883,\n \"type\":1\n },\n {\n \"id\":12,\n \"message\":\"Options were saved successfully.\",\n \"timestamp\":1507969128055,\n \"type\":1\n },\n {\n \"id\":13,\n \"message\":\"qBittorrent is successfully listening on interface :: port: TCP/19036\",\n \"timestamp\":1507969128270,\n \"type\":2\n },\n {\n \"id\":14,\n \"message\":\"qBittorrent is successfully listening on interface 0.0.0.0 port: TCP/19036\",\n \"timestamp\":1507969128271,\n \"type\":2\n },\n {\n \"id\":15,\n \"message\":\"qBittorrent is successfully listening on interface 0.0.0.0 port: UDP/19036\",\n \"timestamp\":1507969128272,\n \"type\":2\n }\n]\n```", + "The response is a JSON array in which each element is an entry of the log.\n\nEach element of the array has the following properties:\n\n\nExample:\n\n```JSON\n[\n {\n \"id\":0,\n \"message\":\"qBittorrent v3.4.0 started\",\n \"timestamp\":1507969127860,\n \"type\":1\n },\n {\n \"id\":1,\n \"message\":\"qBittorrent is trying to listen on any interface port: 19036\",\n \"timestamp\":1507969127869,\n \"type\":2\n },\n {\n \"id\":2,\n \"message\":\"Peer ID: -qB3400-\",\n \"timestamp\":1507969127870,\n \"type\":1\n },\n {\n \"id\":3,\n \"message\":\"HTTP User-Agent is 'qBittorrent/3.4.0'\",\n \"timestamp\":1507969127870,\n \"type\":1\n },\n {\n \"id\":4,\n \"message\":\"DHT support [ON]\",\n \"timestamp\":1507969127871,\n \"type\":2\n },\n {\n \"id\":5,\n \"message\":\"Local Peer Discovery support [ON]\",\n \"timestamp\":1507969127871,\n \"type\":2\n },\n {\n \"id\":6,\n \"message\":\"PeX support [ON]\",\n \"timestamp\":1507969127871,\n \"type\":2\n },\n {\n \"id\":7,\n \"message\":\"Anonymous mode [OFF]\",\n \"timestamp\":1507969127871,\n \"type\":2\n },\n {\n \"id\":8,\n \"message\":\"Encryption support [ON]\",\n \"timestamp\":1507969127871,\n \"type\":2\n },\n {\n \"id\":9,\n \"message\":\"Embedded Tracker [OFF]\",\n \"timestamp\":1507969127871,\n \"type\":2\n },\n {\n \"id\":10,\n \"message\":\"UPnP / NAT-PMP support [ON]\",\n \"timestamp\":1507969127873,\n \"type\":2\n },\n {\n \"id\":11,\n \"message\":\"Web UI: Now listening on port 8080\",\n \"timestamp\":1507969127883,\n \"type\":1\n },\n {\n \"id\":12,\n \"message\":\"Options were saved successfully.\",\n \"timestamp\":1507969128055,\n \"type\":1\n },\n {\n \"id\":13,\n \"message\":\"qBittorrent is successfully listening on interface :: port: TCP/19036\",\n \"timestamp\":1507969128270,\n \"type\":2\n },\n {\n \"id\":14,\n \"message\":\"qBittorrent is successfully listening on interface 0.0.0.0 port: TCP/19036\",\n \"timestamp\":1507969128271,\n \"type\":2\n },\n {\n \"id\":15,\n \"message\":\"qBittorrent is successfully listening on interface 0.0.0.0 port: UDP/19036\",\n \"timestamp\":1507969128272,\n \"type\":2\n }\n]\n```", ), parameters: Some( [ @@ -2720,7 +2728,9 @@ }, ApiMethod { name: "peers", - description: None, + description: Some( + "The response a JSON array. Each element of the array of objects (each object is the information relative to a peer) containing the following fields", + ), parameters: Some( [ Number( @@ -2751,7 +2761,7 @@ ApiMethod { name: "maindata", description: Some( - "Example:\n\n```JSON\n{\n \"rid\":15,\n \"torrents\":\n {\n \"8c212779b4abde7c6bc608063a0d008b7e40ce32\":\n {\n \"state\":\"pausedUP\"\n }\n }\n}\n```", + "The response is a JSON object with the following possible fields\n\n\nExample:\n\n```JSON\n{\n \"rid\":15,\n \"torrents\":\n {\n \"8c212779b4abde7c6bc608063a0d008b7e40ce32\":\n {\n \"state\":\"pausedUP\"\n }\n }\n}\n```", ), parameters: Some( [ @@ -2914,7 +2924,9 @@ }, ApiMethod { name: "torrentPeers", - description: None, + description: Some( + "The response is TODO", + ), parameters: Some( [ String( @@ -2956,7 +2968,7 @@ ApiMethod { name: "info", description: Some( - "In addition to the above in partial data requests (see [Get partial data](#get-partial-data) for more info):\n\nPossible values of `connection_status`:\n\nExample:\n\n```JSON\n{\n \"connection_status\":\"connected\",\n \"dht_nodes\":386,\n \"dl_info_data\":681521119,\n \"dl_info_speed\":0,\n \"dl_rate_limit\":0,\n \"up_info_data\":10747904,\n \"up_info_speed\":0,\n \"up_rate_limit\":1048576\n}\n```", + "The response is a JSON object with the following fields\n\n\nIn addition to the above in partial data requests (see [Get partial data](#get-partial-data) for more info):\n\n\nPossible values of `connection_status`:\n\n\nExample:\n\n```JSON\n{\n \"connection_status\":\"connected\",\n \"dht_nodes\":386,\n \"dl_info_data\":681521119,\n \"dl_info_speed\":0,\n \"dl_rate_limit\":0,\n \"up_info_data\":10747904,\n \"up_info_speed\":0,\n \"up_rate_limit\":1048576\n}\n```", ), parameters: None, return_type: Some( @@ -3107,7 +3119,9 @@ }, ApiMethod { name: "speedLimitsMode", - description: None, + description: Some( + "The response is `1` if alternative speed limits are enabled, `0` otherwise.", + ), parameters: None, return_type: None, url: "speedLimitsMode", @@ -3121,7 +3135,9 @@ }, ApiMethod { name: "downloadLimit", - description: None, + description: Some( + "The response is the value of current global download speed limit in bytes/second; this value will be zero if no limit is applied.", + ), parameters: None, return_type: None, url: "downloadLimit", @@ -3149,7 +3165,9 @@ }, ApiMethod { name: "uploadLimit", - description: None, + description: Some( + "The response is the value of current global upload speed limit in bytes/second; this value will be zero if no limit is applied.", + ), parameters: None, return_type: None, url: "uploadLimit", @@ -3208,7 +3226,7 @@ ApiMethod { name: "info", description: Some( - "Possible values of `state`:\n\nExample:\n\n```JSON\n[\n {\n \"dlspeed\":9681262,\n \"eta\":87,\n \"f_l_piece_prio\":false,\n \"force_start\":false,\n \"hash\":\"8c212779b4abde7c6bc608063a0d008b7e40ce32\",\n \"category\":\"\",\n \"tags\": \"\",\n \"name\":\"debian-8.1.0-amd64-CD-1.iso\",\n \"num_complete\":-1,\n \"num_incomplete\":-1,\n \"num_leechs\":2,\n \"num_seeds\":54,\n \"priority\":1,\n \"progress\":0.16108787059783936,\n \"ratio\":0,\n \"seq_dl\":false,\n \"size\":657457152,\n \"state\":\"downloading\",\n \"super_seeding\":false,\n \"upspeed\":0\n },\n {\n another_torrent_info\n }\n]\n```", + "The response is a JSON array with the following fields\n\n\nPossible values of `state`:\n\n\nExample:\n\n```JSON\n[\n {\n \"dlspeed\":9681262,\n \"eta\":87,\n \"f_l_piece_prio\":false,\n \"force_start\":false,\n \"hash\":\"8c212779b4abde7c6bc608063a0d008b7e40ce32\",\n \"category\":\"\",\n \"tags\": \"\",\n \"name\":\"debian-8.1.0-amd64-CD-1.iso\",\n \"num_complete\":-1,\n \"num_incomplete\":-1,\n \"num_leechs\":2,\n \"num_seeds\":54,\n \"priority\":1,\n \"progress\":0.16108787059783936,\n \"ratio\":0,\n \"seq_dl\":false,\n \"size\":657457152,\n \"state\":\"downloading\",\n \"super_seeding\":false,\n \"upspeed\":0\n },\n {\n another_torrent_info\n }\n]\n```", ), parameters: Some( [ @@ -4070,7 +4088,7 @@ ApiMethod { name: "properties", description: Some( - "- empty, if the torrent hash is invalid\n- otherwise, a JSON object with the following fields\n\nNB: `-1` is returned if the type of the property is integer but its value is not known.\n\nExample:\n\n```JSON\n{\n \"addition_date\":1438429165,\n \"comment\":\"\\\"Debian CD from cdimage.debian.org\\\"\",\n \"completion_date\":1438429234,\n \"created_by\":\"\",\n \"creation_date\":1433605214,\n \"dl_limit\":-1,\n \"dl_speed\":0,\n \"dl_speed_avg\":9736015,\n \"eta\":8640000,\n \"last_seen\":1438430354,\n \"nb_connections\":3,\n \"nb_connections_limit\":250,\n \"peers\":1,\n \"peers_total\":89,\n \"piece_size\":524288,\n \"pieces_have\":1254,\n \"pieces_num\":1254,\n \"reannounce\":672,\n \"save_path\":\"/Downloads/debian-8.1.0-amd64-CD-1.iso\",\n \"seeding_time\":1128,\n \"seeds\":1,\n \"seeds_total\":254,\n \"share_ratio\":0.00072121022562178299,\n \"time_elapsed\":1197,\n \"total_downloaded\":681521119,\n \"total_downloaded_session\":681521119,\n \"total_size\":657457152,\n \"total_uploaded\":491520,\n \"total_uploaded_session\":491520,\n \"total_wasted\":23481724,\n \"up_limit\":-1,\n \"up_speed\":0,\n \"up_speed_avg\":410\n}\n```", + "The response is:\n\n- empty, if the torrent hash is invalid\n- otherwise, a JSON object with the following fields\n\n\nNB: `-1` is returned if the type of the property is integer but its value is not known.\n\nExample:\n\n```JSON\n{\n \"addition_date\":1438429165,\n \"comment\":\"\\\"Debian CD from cdimage.debian.org\\\"\",\n \"completion_date\":1438429234,\n \"created_by\":\"\",\n \"creation_date\":1433605214,\n \"dl_limit\":-1,\n \"dl_speed\":0,\n \"dl_speed_avg\":9736015,\n \"eta\":8640000,\n \"last_seen\":1438430354,\n \"nb_connections\":3,\n \"nb_connections_limit\":250,\n \"peers\":1,\n \"peers_total\":89,\n \"piece_size\":524288,\n \"pieces_have\":1254,\n \"pieces_num\":1254,\n \"reannounce\":672,\n \"save_path\":\"/Downloads/debian-8.1.0-amd64-CD-1.iso\",\n \"seeding_time\":1128,\n \"seeds\":1,\n \"seeds_total\":254,\n \"share_ratio\":0.00072121022562178299,\n \"time_elapsed\":1197,\n \"total_downloaded\":681521119,\n \"total_downloaded_session\":681521119,\n \"total_size\":657457152,\n \"total_uploaded\":491520,\n \"total_uploaded_session\":491520,\n \"total_wasted\":23481724,\n \"up_limit\":-1,\n \"up_speed\":0,\n \"up_speed_avg\":410\n}\n```", ), parameters: Some( [ @@ -4093,7 +4111,7 @@ ApiMethod { name: "trackers", description: Some( - "Possible values of `status`:\n\nExample:\n\n```JSON\n[\n {\n \"msg\":\"\",\n \"num_peers\":100,\n \"status\":2,\n \"url\":\"http://bttracker.debian.org:6969/announce\"\n },\n {\n another_tracker_info\n }\n]\n```", + "The response is a JSON array, where each element contains info about one tracker, with the following fields\n\n\nPossible values of `status`:\n\n\nExample:\n\n```JSON\n[\n {\n \"msg\":\"\",\n \"num_peers\":100,\n \"status\":2,\n \"url\":\"http://bttracker.debian.org:6969/announce\"\n },\n {\n another_tracker_info\n }\n]\n```", ), parameters: Some( [ @@ -4267,7 +4285,7 @@ ApiMethod { name: "webseeds", description: Some( - "Example:\n\n```JSON\n[\n {\n \"url\":\"http://some_url/\"\n },\n {\n \"url\":\"http://some_other_url/\"\n }\n]\n```", + "The response is a JSON array, where each element is information about one webseed, with the following fields\n\n\nExample:\n\n```JSON\n[\n {\n \"url\":\"http://some_url/\"\n },\n {\n \"url\":\"http://some_other_url/\"\n }\n]\n```", ), parameters: Some( [ @@ -4311,7 +4329,7 @@ ApiMethod { name: "files", description: Some( - "- empty, if the torrent hash is invalid\n- otherwise, a JSON array, where each element contains info about one file, with the following fields\n\nPossible values of `priority`:\n\nExample:\n\n```JSON\n\n[\n {\n \"index\":0,\n \"is_seed\":false,\n \"name\":\"debian-8.1.0-amd64-CD-1.iso\",\n \"piece_range\":[0,1253],\n \"priority\":1,\n \"progress\":0,\n \"size\":657457152,\n \"availability\":0.5,\n }\n]\n```", + "The response is:\n\n- empty, if the torrent hash is invalid\n- otherwise, a JSON array, where each element contains info about one file, with the following fields\n\n\nPossible values of `priority`:\n\n\nExample:\n\n```JSON\n\n[\n {\n \"index\":0,\n \"is_seed\":false,\n \"name\":\"debian-8.1.0-amd64-CD-1.iso\",\n \"piece_range\":[0,1253],\n \"priority\":1,\n \"progress\":0,\n \"size\":657457152,\n \"availability\":0.5,\n }\n]\n```", ), parameters: Some( [ @@ -4345,7 +4363,7 @@ ApiMethod { name: "pieceStates", description: Some( - "- empty, if the torrent hash is invalid\n- otherwise, an array of states (integers) of all pieces (in order) of a specific torrent.\n\nValue meanings are defined as below:\n\nExample:\n\n```JSON\n[0,0,2,1,0,0,2,1]\n```", + "The response is:\n\n- empty, if the torrent hash is invalid\n- otherwise, an array of states (integers) of all pieces (in order) of a specific torrent.\n\nValue meanings are defined as below:\n\n\nExample:\n\n```JSON\n[0,0,2,1,0,0,2,1]\n```", ), parameters: Some( [ @@ -4368,7 +4386,7 @@ ApiMethod { name: "pieceHashes", description: Some( - "- empty, if the torrent hash is invalid\n- otherwise, an array of hashes (strings) of all pieces (in order) of a specific torrent.\n\nExample:\n\n```JSON\n[\"54eddd830a5b58480a6143d616a97e3a6c23c439\",\"f8a99d225aa4241db100f88407fc3bdaead583ab\",\"928fb615b9bd4dd8f9e9022552c8f8f37ef76f58\"]\n```", + "The response is:\n\n- empty, if the torrent hash is invalid\n- otherwise, an array of hashes (strings) of all pieces (in order) of a specific torrent.\n\nExample:\n\n```JSON\n[\"54eddd830a5b58480a6143d616a97e3a6c23c439\",\"f8a99d225aa4241db100f88407fc3bdaead583ab\",\"928fb615b9bd4dd8f9e9022552c8f8f37ef76f58\"]\n```", ), parameters: Some( [ @@ -5481,7 +5499,7 @@ ApiMethod { name: "start", description: Some( - "Example:\n\n```JSON\n{\n \"id\": 12345\n}\n```", + "The response is a JSON object with the following fields\n\n\nExample:\n\n```JSON\n{\n \"id\": 12345\n}\n```", ), parameters: Some( [ @@ -5568,7 +5586,7 @@ ApiMethod { name: "status", description: Some( - "Example:\n\n```JSON\n[\n {\n \"id\": 12345,\n \"status\": \"Running\",\n \"total\": 170\n }\n]\n```", + "The response is a JSON array of objects containing the following fields\n\n\nExample:\n\n```JSON\n[\n {\n \"id\": 12345,\n \"status\": \"Running\",\n \"total\": 170\n }\n]\n```", ), parameters: Some( [ @@ -5641,7 +5659,9 @@ }, ApiMethod { name: "results", - description: None, + description: Some( + "The response is a JSON object with the following fields\n\n\n\n\nExample:\n\n```JSON\n{\n \"results\": [\n {\n \"descrLink\": \"http://www.legittorrents.info/index.php?page=torrent-details&id=8d5f512e1acb687029b8d7cc6c5a84dce51d7a41\",\n \"fileName\": \"Ubuntu-10.04-32bit-NeTV.ova\",\n \"fileSize\": -1,\n \"fileUrl\": \"http://www.legittorrents.info/download.php?id=8d5f512e1acb687029b8d7cc6c5a84dce51d7a41&f=Ubuntu-10.04-32bit-NeTV.ova.torrent\",\n \"nbLeechers\": 1,\n \"nbSeeders\": 0,\n \"siteUrl\": \"http://www.legittorrents.info\"\n },\n {\n \"descrLink\": \"http://www.legittorrents.info/index.php?page=torrent-details&id=d5179f53e105dc2c2401bcfaa0c2c4936a6aa475\",\n \"fileName\": \"mangOH-Legato-17_06-Ubuntu-16_04.ova\",\n \"fileSize\": -1,\n \"fileUrl\": \"http://www.legittorrents.info/download.php?id=d5179f53e105dc2c2401bcfaa0c2c4936a6aa475&f=mangOH-Legato-17_06-Ubuntu-16_04.ova.torrent\",\n \"nbLeechers\": 0,\n \"nbSeeders\": 59,\n \"siteUrl\": \"http://www.legittorrents.info\"\n }\n ],\n \"status\": \"Running\",\n \"total\": 2\n}\n```", + ), parameters: Some( [ Number( @@ -5682,11 +5702,264 @@ return_type: Some( ReturnType { is_list: false, - parameters: [], + parameters: [ + ReturnTypeParameter { + name: "results", + description: "Array of result objects- see table below", + return_type: StringArray( + TypeInfo { + name: "results", + is_optional: false, + is_list: false, + description: Some( + "Array of result objects- see table below", + ), + type_description: None, + }, + ), + }, + ReturnTypeParameter { + name: "status", + description: "Current status of the search job (either Running or Stopped)", + return_type: String( + TypeInfo { + name: "status", + is_optional: false, + is_list: false, + description: Some( + "Current status of the search job (either Running or Stopped)", + ), + type_description: None, + }, + ), + }, + ReturnTypeParameter { + name: "total", + description: "Total number of results. If the status is Running this number may continue to increase", + return_type: Number( + TypeInfo { + name: "total", + is_optional: false, + is_list: false, + description: Some( + "Total number of results. If the status is Running this number may continue to increase", + ), + type_description: None, + }, + ), + }, + ], }, ), url: "results", }, + ApiMethod { + name: "delete", + description: None, + parameters: Some( + [ + Number( + TypeInfo { + name: "id", + is_optional: false, + is_list: false, + description: Some( + "ID of the search job", + ), + type_description: None, + }, + ), + ], + ), + return_type: None, + url: "delete", + }, + ApiMethod { + name: "plugins", + description: Some( + "The response is a JSON array of objects containing the following fields\n\n\n```JSON\n[\n {\n \"enabled\": true,\n \"fullName\": \"Legit Torrents\",\n \"name\": \"legittorrents\",\n \"supportedCategories\": [{\n \"id\": \"all\",\n \"name\": \"All categories\"\n }, {\n \"id\": \"anime\",\n \"name\": \"Anime\"\n }, {\n \"id\": \"books\",\n \"name\": \"Books\"\n }, {\n \"id\": \"games\",\n \"name\": \"Games\"\n }, {\n \"id\": \"movies\",\n \"name\": \"Movies\"\n }, {\n \"id\": \"music\",\n \"name\": \"Music\"\n }, {\n \"id\": \"tv\",\n \"name\": \"TV shows\"\n }],\n \"url\": \"http://www.legittorrents.info\",\n \"version\": \"2.3\"\n }\n]\n```", + ), + parameters: None, + return_type: Some( + ReturnType { + is_list: true, + parameters: [ + ReturnTypeParameter { + name: "enabled", + description: "Whether the plugin is enabled", + return_type: Bool( + TypeInfo { + name: "enabled", + is_optional: false, + is_list: false, + description: Some( + "Whether the plugin is enabled", + ), + type_description: None, + }, + ), + }, + ReturnTypeParameter { + name: "fullName", + description: "Full name of the plugin", + return_type: String( + TypeInfo { + name: "fullName", + is_optional: false, + is_list: false, + description: Some( + "Full name of the plugin", + ), + type_description: None, + }, + ), + }, + ReturnTypeParameter { + name: "name", + description: "Short name of the plugin", + return_type: String( + TypeInfo { + name: "name", + is_optional: false, + is_list: false, + description: Some( + "Short name of the plugin", + ), + type_description: None, + }, + ), + }, + ReturnTypeParameter { + name: "supportedCategories", + description: "List of category objects", + return_type: StringArray( + TypeInfo { + name: "supportedCategories", + is_optional: false, + is_list: false, + description: Some( + "List of category objects", + ), + type_description: None, + }, + ), + }, + ReturnTypeParameter { + name: "url", + description: "URL of the torrent site", + return_type: String( + TypeInfo { + name: "url", + is_optional: false, + is_list: false, + description: Some( + "URL of the torrent site", + ), + type_description: None, + }, + ), + }, + ReturnTypeParameter { + name: "version", + description: "Installed version of the plugin", + return_type: String( + TypeInfo { + name: "version", + is_optional: false, + is_list: false, + description: Some( + "Installed version of the plugin", + ), + type_description: None, + }, + ), + }, + ], + }, + ), + url: "plugins", + }, + ApiMethod { + name: "installPlugin", + description: None, + parameters: Some( + [ + String( + TypeInfo { + name: "sources", + is_optional: false, + is_list: false, + description: Some( + "Url or file path of the plugin to install (e.g. \"[https://raw.githubusercontent.com/qbittorrent/search-plugins/master/nova3/engines/legittorrents.py](https://raw.githubusercontent.com/qbittorrent/search-plugins/master/nova3/engines/legittorrents.py)\"). Supports multiple sources separated by \\", + ), + type_description: None, + }, + ), + ], + ), + return_type: None, + url: "installPlugin", + }, + ApiMethod { + name: "uninstallPlugin", + description: None, + parameters: Some( + [ + String( + TypeInfo { + name: "names", + is_optional: false, + is_list: false, + description: Some( + "Name of the plugin to uninstall (e.g. \"legittorrents\"). Supports multiple names separated by \\", + ), + type_description: None, + }, + ), + ], + ), + return_type: None, + url: "uninstallPlugin", + }, + ApiMethod { + name: "enablePlugin", + description: None, + parameters: Some( + [ + String( + TypeInfo { + name: "names", + is_optional: false, + is_list: false, + description: Some( + "Name of the plugin to enable/disable (e.g. \"legittorrents\"). Supports multiple names separated by \\", + ), + type_description: None, + }, + ), + Bool( + TypeInfo { + name: "enable", + is_optional: false, + is_list: false, + description: Some( + "Whether the plugins should be enabled", + ), + type_description: None, + }, + ), + ], + ), + return_type: None, + url: "enablePlugin", + }, + ApiMethod { + name: "updatePlugins", + description: None, + parameters: None, + return_type: None, + url: "updatePlugins", + }, ], description: Some( "All Search API methods are under \"search\", e.g.: `/api/v2/search/methodName`.", diff --git a/qbittorrent-web-api-gen/tests/search_types.rs b/qbittorrent-web-api-gen/tests/search_types.rs new file mode 100644 index 0000000..f4000e0 --- /dev/null +++ b/qbittorrent-web-api-gen/tests/search_types.rs @@ -0,0 +1,20 @@ +mod common; + +use anyhow::Result; +use common::*; +use qbittorrent_web_api_gen::QBittorrentApiGen; + +#[derive(QBittorrentApiGen)] +struct Api {} + +#[tokio::main] +async fn main() -> Result<()> { + let api = Api::login(BASE_URL, USERNAME, PASSWORD).await?; + + let _ = api.search().plugins().await?; + let _ = api.search().results(1).send().await?; + let _ = api.search().delete(1).await?; + let _ = api.search().install_plugin("https://raw.githubusercontent.com/qbittorrent/search-plugins/master/nova3/engines/legittorrents.py").await?; + + Ok(()) +} diff --git a/qbittorrent-web-api-gen/tests/tests.rs b/qbittorrent-web-api-gen/tests/tests.rs index 548499f..873c7ba 100644 --- a/qbittorrent-web-api-gen/tests/tests.rs +++ b/qbittorrent-web-api-gen/tests/tests.rs @@ -20,5 +20,5 @@ fn tests() { t.pass("tests/add_torrent.rs"); t.pass("tests/another_struct_name.rs"); t.pass("tests/access_impl_types.rs"); - // t.pass("tests/search_types.rs"); + t.pass("tests/search_types.rs"); } diff --git a/qbittorrent-web-api-gen/token_tree.txt b/qbittorrent-web-api-gen/token_tree.txt index 52bd36c..db4b5e6 100644 --- a/qbittorrent-web-api-gen/token_tree.txt +++ b/qbittorrent-web-api-gen/token_tree.txt @@ -862,6 +862,9 @@ TokenTree { ], }, ), + Text( + "", + ), Asterix( "Returns:", ), @@ -896,6 +899,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "Upon success, the response will contain a cookie with your SID. You must supply the cookie whenever you want to perform an operation that requires authentication.", ), @@ -1000,6 +1006,9 @@ TokenTree { ], }, ), + Text( + "", + ), ], children: [], }, @@ -1074,6 +1083,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "The response is a string with the application version, e.g. `v4.1.3`", ), @@ -1136,6 +1148,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "The response is a string with the WebAPI version, e.g. `2.0`", ), @@ -1198,6 +1213,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "The response is a JSON object containing the following fields", ), @@ -1259,6 +1277,9 @@ TokenTree { ], }, ), + Text( + "", + ), ], children: [], }, @@ -1315,6 +1336,9 @@ TokenTree { ], }, ), + Text( + "", + ), ], children: [], }, @@ -1371,6 +1395,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "The response is a JSON object with several fields (key-value) pairs representing the application's settings. The contents may vary depending on which settings are present in qBittorrent.ini.", ), @@ -2566,6 +2593,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "Possible values of `scan_dirs`:", ), @@ -2607,6 +2637,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "Possible values of `scheduler_days`:", ), @@ -2697,6 +2730,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "Possible values of `encryption`:", ), @@ -2738,6 +2774,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "NB: the first options allows you to use both encrypted and unencrypted connections (this is the default); other options are mutually exclusive: e.g. by forcing encryption on you won't be able to use unencrypted connections and vice versa.", ), @@ -2806,6 +2845,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "Possible values of `dyndns_service`:", ), @@ -2840,6 +2882,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "Possible values of `max_ratio_act`:", ), @@ -2874,6 +2919,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "Possible values of `bittorrent_protocol`:", ), @@ -2915,6 +2963,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "Possible values of `upload_choking_algorithm`:", ), @@ -2956,6 +3007,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "Possible values of `upload_slots_behavior`:", ), @@ -2990,6 +3044,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "Possible values of `utp_tcp_mixed_mode`:", ), @@ -3024,6 +3081,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "Example:", ), @@ -3557,6 +3617,9 @@ TokenTree { ], }, ), + Text( + "", + ), Asterix( "Notes**:", ), @@ -3637,6 +3700,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "The response is a string with the default save path, e.g. `C:/Users/Dayman/Downloads`.", ), @@ -3739,6 +3805,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "Example:", ), @@ -3784,6 +3853,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "The response is a JSON array in which each element is an entry of the log.", ), @@ -3843,6 +3915,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "Example:", ), @@ -4198,6 +4273,9 @@ TokenTree { ], }, ), + Text( + "", + ), Asterix( "Returns:", ), @@ -4225,6 +4303,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "The response a JSON array. Each element of the array of objects (each object is the information relative to a peer) containing the following fields", ), @@ -4286,6 +4367,9 @@ TokenTree { ], }, ), + Text( + "", + ), ], children: [], }, @@ -4353,6 +4437,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "Example:", ), @@ -4398,6 +4485,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "The response is a JSON object with the following possible fields", ), @@ -4491,6 +4581,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "Example:", ), @@ -4590,6 +4683,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "Example:", ), @@ -4642,6 +4738,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "The response is TODO", ), @@ -4728,6 +4827,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "The response is a JSON object with the following fields", ), @@ -4813,6 +4915,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "In addition to the above in partial data requests (see [Get partial data](#get-partial-data) for more info):", ), @@ -4858,6 +4963,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "Possible values of `connection_status`:", ), @@ -4899,6 +5007,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "Example:", ), @@ -5000,6 +5111,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "The response is `1` if alternative speed limits are enabled, `0` otherwise.", ), @@ -5062,6 +5176,9 @@ TokenTree { ], }, ), + Text( + "", + ), ], children: [], }, @@ -5118,6 +5235,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "The response is the value of current global download speed limit in bytes/second; this value will be zero if no limit is applied.", ), @@ -5170,6 +5290,9 @@ TokenTree { ], }, ), + Text( + "", + ), Asterix( "Returns:", ), @@ -5197,6 +5320,9 @@ TokenTree { ], }, ), + Text( + "", + ), ], children: [], }, @@ -5253,6 +5379,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "The response is the value of current global upload speed limit in bytes/second; this value will be zero if no limit is applied.", ), @@ -5305,6 +5434,9 @@ TokenTree { ], }, ), + Text( + "", + ), Asterix( "Returns:", ), @@ -5332,6 +5464,9 @@ TokenTree { ], }, ), + Text( + "", + ), ], children: [], }, @@ -5379,6 +5514,9 @@ TokenTree { ], }, ), + Text( + "", + ), Asterix( "Returns:", ), @@ -5406,6 +5544,9 @@ TokenTree { ], }, ), + Text( + "", + ), ], children: [], }, @@ -5527,6 +5668,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "Example:", ), @@ -5572,6 +5716,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "The response is a JSON array with the following fields", ), @@ -5953,6 +6100,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "Possible values of `state`:", ), @@ -6106,6 +6256,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "Example:", ), @@ -6254,6 +6407,9 @@ TokenTree { ], }, ), + Text( + "", + ), Asterix( "Returns:", ), @@ -6288,6 +6444,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "The response is:", ), @@ -6582,6 +6741,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "NB: `-1` is returned if the type of the property is integer but its value is not known.", ), @@ -6760,6 +6922,9 @@ TokenTree { ], }, ), + Text( + "", + ), Asterix( "Returns:", ), @@ -6794,6 +6959,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "The response is a JSON array, where each element contains info about one tracker, with the following fields", ), @@ -6879,6 +7047,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "Possible values of `status`:", ), @@ -6934,6 +7105,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "Example:", ), @@ -7034,6 +7208,9 @@ TokenTree { ], }, ), + Text( + "", + ), Asterix( "Returns:", ), @@ -7068,6 +7245,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "The response is a JSON array, where each element is information about one webseed, with the following fields", ), @@ -7097,6 +7277,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "Example:", ), @@ -7197,6 +7380,9 @@ TokenTree { ], }, ), + Text( + "", + ), Asterix( "Returns:", ), @@ -7231,6 +7417,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "The response is:", ), @@ -7325,6 +7514,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "Possible values of `priority`:", ), @@ -7373,6 +7565,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "Example:", ), @@ -7479,6 +7674,9 @@ TokenTree { ], }, ), + Text( + "", + ), Asterix( "Returns:", ), @@ -7513,6 +7711,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "The response is:", ), @@ -7569,6 +7770,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "Example:", ), @@ -7639,6 +7843,9 @@ TokenTree { ], }, ), + Text( + "", + ), Asterix( "Returns:", ), @@ -7673,6 +7880,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "The response is:", ), @@ -7759,6 +7969,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "Example:", ), @@ -7781,6 +7994,9 @@ TokenTree { rows: [], }, ), + Text( + "", + ), Asterix( "Returns:", ), @@ -7808,6 +8024,9 @@ TokenTree { ], }, ), + Text( + "", + ), ], children: [], }, @@ -7861,6 +8080,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "Example:", ), @@ -7883,6 +8105,9 @@ TokenTree { rows: [], }, ), + Text( + "", + ), Asterix( "Returns:", ), @@ -7910,6 +8135,9 @@ TokenTree { ], }, ), + Text( + "", + ), ], children: [], }, @@ -7970,6 +8198,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "Example:", ), @@ -8015,6 +8246,9 @@ TokenTree { ], }, ), + Text( + "", + ), ], children: [], }, @@ -8068,6 +8302,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "Example:", ), @@ -8090,6 +8327,9 @@ TokenTree { rows: [], }, ), + Text( + "", + ), Asterix( "Returns:", ), @@ -8117,6 +8357,9 @@ TokenTree { ], }, ), + Text( + "", + ), ], children: [], }, @@ -8170,6 +8413,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "Example:", ), @@ -8192,6 +8438,9 @@ TokenTree { rows: [], }, ), + Text( + "", + ), Asterix( "Returns:", ), @@ -8219,6 +8468,9 @@ TokenTree { ], }, ), + Text( + "", + ), ], children: [], }, @@ -8603,6 +8855,9 @@ TokenTree { ], }, ), + Text( + "", + ), Asterix( "Returns:", ), @@ -8637,6 +8892,9 @@ TokenTree { ], }, ), + Text( + "", + ), ], children: [], }, @@ -8733,6 +8991,9 @@ TokenTree { ], }, ), + Text( + "", + ), ], children: [], }, @@ -8795,6 +9056,9 @@ TokenTree { ], }, ), + Text( + "", + ), Asterix( "Returns:", ), @@ -8850,6 +9114,9 @@ TokenTree { ], }, ), + Text( + "", + ), ], children: [], }, @@ -8905,6 +9172,9 @@ TokenTree { ], }, ), + Text( + "", + ), Asterix( "Returns:", ), @@ -8946,6 +9216,9 @@ TokenTree { ], }, ), + Text( + "", + ), ], children: [], }, @@ -9002,6 +9275,9 @@ TokenTree { ], }, ), + Text( + "", + ), Asterix( "Returns:", ), @@ -9036,6 +9312,9 @@ TokenTree { ], }, ), + Text( + "", + ), ], children: [], }, @@ -9089,6 +9368,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "Example:", ), @@ -9111,6 +9393,9 @@ TokenTree { rows: [], }, ), + Text( + "", + ), Asterix( "Returns:", ), @@ -9145,6 +9430,9 @@ TokenTree { ], }, ), + Text( + "", + ), ], children: [], }, @@ -9198,6 +9486,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "Example:", ), @@ -9220,6 +9511,9 @@ TokenTree { rows: [], }, ), + Text( + "", + ), Asterix( "Returns:", ), @@ -9254,6 +9548,9 @@ TokenTree { ], }, ), + Text( + "", + ), ], children: [], }, @@ -9307,6 +9604,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "Example:", ), @@ -9329,6 +9629,9 @@ TokenTree { rows: [], }, ), + Text( + "", + ), Asterix( "Returns:", ), @@ -9363,6 +9666,9 @@ TokenTree { ], }, ), + Text( + "", + ), ], children: [], }, @@ -9416,6 +9722,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "Example:", ), @@ -9438,6 +9747,9 @@ TokenTree { rows: [], }, ), + Text( + "", + ), Asterix( "Returns:", ), @@ -9472,6 +9784,9 @@ TokenTree { ], }, ), + Text( + "", + ), ], children: [], }, @@ -9535,6 +9850,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "`id` values correspond to file position inside the array returned by [torrent contents API](#get-torrent-contents), e.g. `id=0` for first file, `id=1` for second file, etc.", ), @@ -9609,6 +9927,9 @@ TokenTree { ], }, ), + Text( + "", + ), ], children: [], }, @@ -9669,6 +9990,9 @@ TokenTree { rows: [], }, ), + Text( + "", + ), Table( Table { header: TableRow { @@ -9682,6 +10006,9 @@ TokenTree { rows: [], }, ), + Text( + "Server reply (example):", + ), Text( "", ), @@ -9769,6 +10096,9 @@ TokenTree { rows: [], }, ), + Text( + "", + ), Table( Table { header: TableRow { @@ -9782,6 +10112,9 @@ TokenTree { rows: [], }, ), + Text( + "", + ), Asterix( "Returns:", ), @@ -9809,6 +10142,9 @@ TokenTree { ], }, ), + Text( + "", + ), ], children: [], }, @@ -9869,6 +10205,9 @@ TokenTree { rows: [], }, ), + Text( + "", + ), Table( Table { header: TableRow { @@ -9882,6 +10221,9 @@ TokenTree { rows: [], }, ), + Text( + "`seedingTimeLimit` is the max amount of time the torrent should be seeded. `-2` means the global limit should be used, `-1` means no limit.", + ), Text( "", ), @@ -9912,6 +10254,9 @@ TokenTree { ], }, ), + Text( + "", + ), ], children: [], }, @@ -9972,6 +10317,9 @@ TokenTree { rows: [], }, ), + Text( + "", + ), Table( Table { header: TableRow { @@ -9985,6 +10333,9 @@ TokenTree { rows: [], }, ), + Text( + "Server reply (example):", + ), Text( "", ), @@ -10078,6 +10429,9 @@ TokenTree { rows: [], }, ), + Text( + "", + ), Table( Table { header: TableRow { @@ -10091,6 +10445,9 @@ TokenTree { rows: [], }, ), + Text( + "", + ), Asterix( "Returns:", ), @@ -10118,6 +10475,9 @@ TokenTree { ], }, ), + Text( + "", + ), ], children: [], }, @@ -10178,6 +10538,9 @@ TokenTree { rows: [], }, ), + Text( + "", + ), Table( Table { header: TableRow { @@ -10191,6 +10554,9 @@ TokenTree { rows: [], }, ), + Text( + "", + ), Asterix( "Returns:", ), @@ -10239,6 +10605,9 @@ TokenTree { ], }, ), + Text( + "", + ), ], children: [], }, @@ -10336,6 +10705,9 @@ TokenTree { ], }, ), + Text( + "", + ), ], children: [], }, @@ -10396,6 +10768,9 @@ TokenTree { rows: [], }, ), + Text( + "", + ), Table( Table { header: TableRow { @@ -10409,6 +10784,9 @@ TokenTree { rows: [], }, ), + Text( + "`category` is the torrent category you want to set.", + ), Text( "", ), @@ -10446,6 +10824,9 @@ TokenTree { ], }, ), + Text( + "", + ), ], children: [], }, @@ -10544,6 +10925,9 @@ TokenTree { ], }, ), + Text( + "", + ), ], children: [], }, @@ -10641,6 +11025,9 @@ TokenTree { ], }, ), + Text( + "", + ), ], children: [], }, @@ -10732,6 +11119,9 @@ TokenTree { ], }, ), + Text( + "", + ), ], children: [], }, @@ -10815,6 +11205,9 @@ TokenTree { ], }, ), + Text( + "", + ), ], children: [], }, @@ -10875,6 +11268,9 @@ TokenTree { rows: [], }, ), + Text( + "", + ), Table( Table { header: TableRow { @@ -10888,6 +11284,9 @@ TokenTree { rows: [], }, ), + Text( + "`tags` is the list of tags you want to add to passed torrents.", + ), Text( "", ), @@ -10918,6 +11317,9 @@ TokenTree { ], }, ), + Text( + "", + ), ], children: [], }, @@ -10978,6 +11380,9 @@ TokenTree { rows: [], }, ), + Text( + "", + ), Table( Table { header: TableRow { @@ -10991,6 +11396,9 @@ TokenTree { rows: [], }, ), + Text( + "`tags` is the list of tags you want to remove from passed torrents.", + ), Text( "Empty list removes all tags from relevant torrents.", ), @@ -11024,6 +11432,9 @@ TokenTree { ], }, ), + Text( + "", + ), ], children: [], }, @@ -11104,6 +11515,9 @@ TokenTree { ], }, ), + Text( + "", + ), ], children: [], }, @@ -11187,6 +11601,9 @@ TokenTree { ], }, ), + Text( + "", + ), ], children: [], }, @@ -11273,6 +11690,9 @@ TokenTree { ], }, ), + Text( + "", + ), ], children: [], }, @@ -11333,6 +11753,9 @@ TokenTree { rows: [], }, ), + Text( + "", + ), Table( Table { header: TableRow { @@ -11346,6 +11769,9 @@ TokenTree { rows: [], }, ), + Text( + "", + ), Asterix( "Returns:", ), @@ -11373,6 +11799,9 @@ TokenTree { ], }, ), + Text( + "", + ), ], children: [], }, @@ -11426,6 +11855,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "Example:", ), @@ -11448,6 +11880,9 @@ TokenTree { rows: [], }, ), + Text( + "", + ), Asterix( "Returns:", ), @@ -11475,6 +11910,9 @@ TokenTree { ], }, ), + Text( + "", + ), ], children: [], }, @@ -11528,6 +11966,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "Example:", ), @@ -11550,6 +11991,9 @@ TokenTree { rows: [], }, ), + Text( + "", + ), Asterix( "Returns:", ), @@ -11577,6 +12021,9 @@ TokenTree { ], }, ), + Text( + "", + ), ], children: [], }, @@ -11646,6 +12093,9 @@ TokenTree { rows: [], }, ), + Text( + "", + ), Asterix( "Returns:", ), @@ -11673,6 +12123,9 @@ TokenTree { ], }, ), + Text( + "", + ), ], children: [], }, @@ -11742,6 +12195,9 @@ TokenTree { rows: [], }, ), + Text( + "", + ), Asterix( "Returns:", ), @@ -11769,6 +12225,9 @@ TokenTree { ], }, ), + Text( + "", + ), ], children: [], }, @@ -11831,6 +12290,9 @@ TokenTree { ], }, ), + Text( + "", + ), Asterix( "Returns:", ), @@ -11872,6 +12334,9 @@ TokenTree { ], }, ), + Text( + "", + ), ], children: [], }, @@ -11934,6 +12399,9 @@ TokenTree { ], }, ), + Text( + "", + ), Asterix( "Returns:", ), @@ -11975,6 +12443,9 @@ TokenTree { ], }, ), + Text( + "", + ), ], children: [], }, @@ -12039,6 +12510,9 @@ TokenTree { ], }, ), + Text( + "", + ), Asterix( "Returns:", ), @@ -12073,6 +12547,9 @@ TokenTree { ], }, ), + Text( + "", + ), ], children: [], }, @@ -12127,6 +12604,9 @@ TokenTree { ], }, ), + Text( + "", + ), Asterix( "Returns:", ), @@ -12161,6 +12641,9 @@ TokenTree { ], }, ), + Text( + "", + ), ], children: [], }, @@ -12213,6 +12696,9 @@ TokenTree { ], }, ), + Text( + "", + ), Asterix( "Returns:", ), @@ -12247,6 +12733,9 @@ TokenTree { ], }, ), + Text( + "", + ), ], children: [], }, @@ -12307,6 +12796,9 @@ TokenTree { ], }, ), + Text( + "", + ), Asterix( "Returns:", ), @@ -12341,6 +12833,9 @@ TokenTree { ], }, ), + Text( + "", + ), ], children: [], }, @@ -12387,6 +12882,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "Returns all RSS items in JSON format, e.g.:", ), @@ -12486,6 +12984,9 @@ TokenTree { ], }, ), + Text( + "", + ), Asterix( "Returns:", ), @@ -12513,6 +13014,9 @@ TokenTree { ], }, ), + Text( + "", + ), ], children: [], }, @@ -12565,6 +13069,9 @@ TokenTree { ], }, ), + Text( + "", + ), Asterix( "Returns:", ), @@ -12592,6 +13099,9 @@ TokenTree { ], }, ), + Text( + "", + ), ], children: [], }, @@ -12646,6 +13156,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "Rule definition is JSON encoded dictionary with the following fields:", ), @@ -12771,6 +13284,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "E.g.:", ), @@ -12894,6 +13410,9 @@ TokenTree { ], }, ), + Text( + "", + ), Asterix( "Returns:", ), @@ -12921,6 +13440,9 @@ TokenTree { ], }, ), + Text( + "", + ), ], children: [], }, @@ -12967,6 +13489,9 @@ TokenTree { ], }, ), + Text( + "", + ), Asterix( "Returns:", ), @@ -12997,6 +13522,9 @@ TokenTree { Text( "", ), + Text( + "", + ), ], children: [], }, @@ -13113,6 +13641,9 @@ TokenTree { ], }, ), + Text( + "", + ), ], children: [], }, @@ -13156,6 +13687,9 @@ TokenTree { Text( "", ), + Text( + "", + ), Text( "Returns all articles that match a rule by feed name in JSON format, e.g.:", ), @@ -13252,6 +13786,9 @@ TokenTree { Text( "", ), + Text( + "", + ), ], children: [], }, @@ -13333,6 +13870,9 @@ TokenTree { ], }, ), + Text( + "", + ), Asterix( "Returns:", ), @@ -13367,6 +13907,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "The response is a JSON object with the following fields", ), @@ -13396,6 +13939,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "Example:", ), @@ -13466,6 +14012,9 @@ TokenTree { ], }, ), + Text( + "", + ), Asterix( "Returns:", ), @@ -13500,6 +14049,9 @@ TokenTree { ], }, ), + Text( + "", + ), ], children: [], }, @@ -13546,6 +14098,9 @@ TokenTree { ], }, ), + Text( + "", + ), Asterix( "Returns:", ), @@ -13580,6 +14135,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "The response is a JSON array of objects containing the following fields", ), @@ -13625,6 +14183,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "Example:", ), @@ -13723,6 +14284,9 @@ TokenTree { ], }, ), + Text( + "", + ), Asterix( "Returns:", ), @@ -13764,6 +14328,9 @@ TokenTree { ], }, ), + Text( + "", + ), Text( "The response is a JSON object with the following fields", ), @@ -13781,13 +14348,854 @@ TokenTree { ], }, split: "----------------------------------|---------|------------", - rows: [], + rows: [ + TableRow { + raw: "`results` | array | Array of `result` objects- see table below", + columns: [ + "results", + "array", + "Array of result objects- see table below", + ], + }, + TableRow { + raw: "`status` | string | Current status of the search job (either `Running` or `Stopped`)", + columns: [ + "status", + "string", + "Current status of the search job (either Running or Stopped)", + ], + }, + TableRow { + raw: "`total` | number | Total number of results. If the status is `Running` this number may continue to increase", + columns: [ + "total", + "number", + "Total number of results. If the status is Running this number may continue to increase", + ], + }, + ], }, ), + Text( + "", + ), + Asterix( + "Result object:", + ), + Text( + "", + ), + Table( + Table { + header: TableRow { + raw: "Field | Type | Description", + columns: [ + "Field", + "Type", + "Description", + ], + }, + split: "----------------------------------|---------|------------", + rows: [ + TableRow { + raw: "`descrLink` | string | URL of the torrent's description page", + columns: [ + "descrLink", + "string", + "URL of the torrent's description page", + ], + }, + TableRow { + raw: "`fileName` | string | Name of the file", + columns: [ + "fileName", + "string", + "Name of the file", + ], + }, + TableRow { + raw: "`fileSize` | number | Size of the file in Bytes", + columns: [ + "fileSize", + "number", + "Size of the file in Bytes", + ], + }, + TableRow { + raw: "`fileUrl` | string | Torrent download link (usually either .torrent file or magnet link)", + columns: [ + "fileUrl", + "string", + "Torrent download link (usually either .torrent file or magnet link)", + ], + }, + TableRow { + raw: "`nbLeechers` | number | Number of leechers", + columns: [ + "nbLeechers", + "number", + "Number of leechers", + ], + }, + TableRow { + raw: "`nbSeeders` | number | Number of seeders", + columns: [ + "nbSeeders", + "number", + "Number of seeders", + ], + }, + TableRow { + raw: "`siteUrl` | string | URL of the torrent site", + columns: [ + "siteUrl", + "string", + "URL of the torrent site", + ], + }, + ], + }, + ), + Text( + "", + ), + Text( + "Example:", + ), + Text( + "", + ), + Text( + "```JSON", + ), + Text( + "{", + ), + Text( + " \"results\": [", + ), + Text( + " {", + ), + Text( + " \"descrLink\": \"http://www.legittorrents.info/index.php?page=torrent-details&id=8d5f512e1acb687029b8d7cc6c5a84dce51d7a41\",", + ), + Text( + " \"fileName\": \"Ubuntu-10.04-32bit-NeTV.ova\",", + ), + Text( + " \"fileSize\": -1,", + ), + Text( + " \"fileUrl\": \"http://www.legittorrents.info/download.php?id=8d5f512e1acb687029b8d7cc6c5a84dce51d7a41&f=Ubuntu-10.04-32bit-NeTV.ova.torrent\",", + ), + Text( + " \"nbLeechers\": 1,", + ), + Text( + " \"nbSeeders\": 0,", + ), + Text( + " \"siteUrl\": \"http://www.legittorrents.info\"", + ), + Text( + " },", + ), + Text( + " {", + ), + Text( + " \"descrLink\": \"http://www.legittorrents.info/index.php?page=torrent-details&id=d5179f53e105dc2c2401bcfaa0c2c4936a6aa475\",", + ), + Text( + " \"fileName\": \"mangOH-Legato-17_06-Ubuntu-16_04.ova\",", + ), + Text( + " \"fileSize\": -1,", + ), + Text( + " \"fileUrl\": \"http://www.legittorrents.info/download.php?id=d5179f53e105dc2c2401bcfaa0c2c4936a6aa475&f=mangOH-Legato-17_06-Ubuntu-16_04.ova.torrent\",", + ), + Text( + " \"nbLeechers\": 0,", + ), + Text( + " \"nbSeeders\": 59,", + ), + Text( + " \"siteUrl\": \"http://www.legittorrents.info\"", + ), + Text( + " }", + ), + Text( + " ],", + ), + Text( + " \"status\": \"Running\",", + ), + Text( + " \"total\": 2", + ), + Text( + "}", + ), + Text( + "```", + ), + Text( + "", + ), + ], + children: [], + }, + TokenTree { + title: Some( + "Delete search", + ), + content: [ + Text( + "", + ), + Text( + "Name: `delete`", + ), + Text( + "", + ), + Asterix( + "Parameters:", + ), + Text( + "", + ), + Table( + Table { + header: TableRow { + raw: "Parameter | Type | Description", + columns: [ + "Parameter", + "Type", + "Description", + ], + }, + split: "----------------------------------|---------|------------", + rows: [ + TableRow { + raw: "`id` | number | ID of the search job", + columns: [ + "id", + "number", + "ID of the search job", + ], + }, + ], + }, + ), + Text( + "", + ), + Asterix( + "Returns:", + ), + Text( + "", + ), + Table( + Table { + header: TableRow { + raw: "HTTP Status Code | Scenario", + columns: [ + "HTTP Status Code", + "Scenario", + ], + }, + split: "----------------------------------|---------------------", + rows: [ + TableRow { + raw: "404 | Search job was not found", + columns: [ + "404", + "Search job was not found", + ], + }, + TableRow { + raw: "200 | All other scenarios", + columns: [ + "200", + "All other scenarios", + ], + }, + ], + }, + ), + Text( + "", + ), + ], + children: [], + }, + TokenTree { + title: Some( + "Get search plugins", + ), + content: [ + Text( + "", + ), + Text( + "Name: `plugins`", + ), + Text( + "", + ), + Asterix( + "Parameters:", + ), + Text( + "", + ), + Text( + "None", + ), + Text( + "", + ), + Asterix( + "Returns:", + ), + Text( + "", + ), + Table( + Table { + header: TableRow { + raw: "HTTP Status Code | Scenario", + columns: [ + "HTTP Status Code", + "Scenario", + ], + }, + split: "----------------------------------|---------------------", + rows: [ + TableRow { + raw: "200 | All scenarios- see JSON below", + columns: [ + "200", + "All scenarios- see JSON below", + ], + }, + ], + }, + ), + Text( + "", + ), + Text( + "The response is a JSON array of objects containing the following fields", + ), + Text( + "", + ), + Table( + Table { + header: TableRow { + raw: "Field | Type | Description", + columns: [ + "Field", + "Type", + "Description", + ], + }, + split: "----------------------------------|---------|------------", + rows: [ + TableRow { + raw: "`enabled` | bool | Whether the plugin is enabled", + columns: [ + "enabled", + "bool", + "Whether the plugin is enabled", + ], + }, + TableRow { + raw: "`fullName` | string | Full name of the plugin", + columns: [ + "fullName", + "string", + "Full name of the plugin", + ], + }, + TableRow { + raw: "`name` | string | Short name of the plugin", + columns: [ + "name", + "string", + "Short name of the plugin", + ], + }, + TableRow { + raw: "`supportedCategories` | array | List of category objects", + columns: [ + "supportedCategories", + "array", + "List of category objects", + ], + }, + TableRow { + raw: "`url` | string | URL of the torrent site", + columns: [ + "url", + "string", + "URL of the torrent site", + ], + }, + TableRow { + raw: "`version` | string | Installed version of the plugin", + columns: [ + "version", + "string", + "Installed version of the plugin", + ], + }, + ], + }, + ), + Text( + "", + ), + Text( + "```JSON", + ), + Text( + "[", + ), + Text( + " {", + ), + Text( + " \"enabled\": true,", + ), + Text( + " \"fullName\": \"Legit Torrents\",", + ), + Text( + " \"name\": \"legittorrents\",", + ), + Text( + " \"supportedCategories\": [{", + ), + Text( + " \"id\": \"all\",", + ), + Text( + " \"name\": \"All categories\"", + ), + Text( + " }, {", + ), + Text( + " \"id\": \"anime\",", + ), + Text( + " \"name\": \"Anime\"", + ), + Text( + " }, {", + ), + Text( + " \"id\": \"books\",", + ), + Text( + " \"name\": \"Books\"", + ), + Text( + " }, {", + ), + Text( + " \"id\": \"games\",", + ), + Text( + " \"name\": \"Games\"", + ), + Text( + " }, {", + ), + Text( + " \"id\": \"movies\",", + ), + Text( + " \"name\": \"Movies\"", + ), + Text( + " }, {", + ), + Text( + " \"id\": \"music\",", + ), + Text( + " \"name\": \"Music\"", + ), + Text( + " }, {", + ), + Text( + " \"id\": \"tv\",", + ), + Text( + " \"name\": \"TV shows\"", + ), + Text( + " }],", + ), + Text( + " \"url\": \"http://www.legittorrents.info\",", + ), + Text( + " \"version\": \"2.3\"", + ), + Text( + " }", + ), + Text( + "]", + ), + Text( + "```", + ), + Text( + "", + ), + ], + children: [], + }, + TokenTree { + title: Some( + "Install search plugin", + ), + content: [ + Text( + "", + ), + Text( + "Name: `installPlugin`", + ), + Text( + "", + ), + Asterix( + "Parameters:", + ), + Text( + "", + ), + Table( + Table { + header: TableRow { + raw: "Parameter | Type | Description", + columns: [ + "Parameter", + "Type", + "Description", + ], + }, + split: "----------------------------------|---------|------------", + rows: [ + TableRow { + raw: "`sources` | string | Url or file path of the plugin to install (e.g. \"[https://raw.githubusercontent.com/qbittorrent/search-plugins/master/nova3/engines/legittorrents.py](https://raw.githubusercontent.com/qbittorrent/search-plugins/master/nova3/engines/legittorrents.py)\"). Supports multiple sources separated by `\\|`", + columns: [ + "sources", + "string", + "Url or file path of the plugin to install (e.g. \"[https://raw.githubusercontent.com/qbittorrent/search-plugins/master/nova3/engines/legittorrents.py](https://raw.githubusercontent.com/qbittorrent/search-plugins/master/nova3/engines/legittorrents.py)\"). Supports multiple sources separated by \\", + "", + ], + }, + ], + }, + ), + Text( + "", + ), + Asterix( + "Returns:", + ), + Text( + "", + ), + Table( + Table { + header: TableRow { + raw: "HTTP Status Code | Scenario", + columns: [ + "HTTP Status Code", + "Scenario", + ], + }, + split: "----------------------------------|---------------------", + rows: [ + TableRow { + raw: "200 | All scenarios", + columns: [ + "200", + "All scenarios", + ], + }, + ], + }, + ), + Text( + "", + ), + ], + children: [], + }, + TokenTree { + title: Some( + "Uninstall search plugin", + ), + content: [ + Text( + "", + ), + Text( + "Name: `uninstallPlugin`", + ), + Text( + "", + ), + Asterix( + "Parameters:", + ), + Text( + "", + ), + Table( + Table { + header: TableRow { + raw: "Parameter | Type | Description", + columns: [ + "Parameter", + "Type", + "Description", + ], + }, + split: "----------------------------------|---------|------------", + rows: [ + TableRow { + raw: "`names` | string | Name of the plugin to uninstall (e.g. \"legittorrents\"). Supports multiple names separated by `\\|`", + columns: [ + "names", + "string", + "Name of the plugin to uninstall (e.g. \"legittorrents\"). Supports multiple names separated by \\", + "", + ], + }, + ], + }, + ), + Text( + "", + ), + Asterix( + "Returns:", + ), + Text( + "", + ), + Table( + Table { + header: TableRow { + raw: "HTTP Status Code | Scenario", + columns: [ + "HTTP Status Code", + "Scenario", + ], + }, + split: "----------------------------------|---------------------", + rows: [ + TableRow { + raw: "200 | All scenarios", + columns: [ + "200", + "All scenarios", + ], + }, + ], + }, + ), + Text( + "", + ), + ], + children: [], + }, + TokenTree { + title: Some( + "Enable search plugin", + ), + content: [ + Text( + "", + ), + Text( + "Name: `enablePlugin`", + ), + Text( + "", + ), + Asterix( + "Parameters:", + ), + Text( + "", + ), + Table( + Table { + header: TableRow { + raw: "Parameter | Type | Description", + columns: [ + "Parameter", + "Type", + "Description", + ], + }, + split: "----------------------------------|---------|------------", + rows: [ + TableRow { + raw: "`names` | string | Name of the plugin to enable/disable (e.g. \"legittorrents\"). Supports multiple names separated by `\\|`", + columns: [ + "names", + "string", + "Name of the plugin to enable/disable (e.g. \"legittorrents\"). Supports multiple names separated by \\", + "", + ], + }, + TableRow { + raw: "`enable` | bool | Whether the plugins should be enabled", + columns: [ + "enable", + "bool", + "Whether the plugins should be enabled", + ], + }, + ], + }, + ), + Text( + "", + ), + Asterix( + "Returns:", + ), + Text( + "", + ), + Table( + Table { + header: TableRow { + raw: "HTTP Status Code | Scenario", + columns: [ + "HTTP Status Code", + "Scenario", + ], + }, + split: "----------------------------------|---------------------", + rows: [ + TableRow { + raw: "200 | All scenarios", + columns: [ + "200", + "All scenarios", + ], + }, + ], + }, + ), + Text( + "", + ), + ], + children: [], + }, + TokenTree { + title: Some( + "Update search plugins", + ), + content: [ + Text( + "", + ), + Text( + "Name: `updatePlugins`", + ), + Text( + "", + ), + Asterix( + "Parameters:", + ), + Text( + "", + ), + Text( + "None", + ), + Text( + "", + ), + Asterix( + "Returns:", + ), + Text( + "", + ), + Table( + Table { + header: TableRow { + raw: "HTTP Status Code | Scenario", + columns: [ + "HTTP Status Code", + "Scenario", + ], + }, + split: "----------------------------------|---------------------", + rows: [ + TableRow { + raw: "200 | All scenarios", + columns: [ + "200", + "All scenarios", + ], + }, + ], + }, + ), + Text( + "", + ), ], children: [], }, ], }, + TokenTree { + title: Some( + "WebAPI versioning", + ), + content: [ + Text( + "WebAPI uses the following versioning: `1.2.3`:", + ), + Text( + "1. Main version. Should be changed only on some global changes (e.g. total redesign/relayout)", + ), + Text( + "2. Changed on incompatible API changes (i.e. if it breaks outdated clients). E.g. if you change/remove something", + ), + Text( + "3. Changed on compatible API changes (i.e. if it doesn't break outdated clients). E.g. if you add something new outdated clients still can access old subset of API.", + ), + ], + children: [], + }, ], } \ No newline at end of file From 79004924ec38edcb54073f2ef4161ad9a1a2fbba Mon Sep 17 00:00:00 2001 From: Joel Wachsler Date: Thu, 14 Jul 2022 18:22:20 +0000 Subject: [PATCH 11/47] Remove test files from package --- qbittorrent-web-api-gen/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qbittorrent-web-api-gen/Cargo.toml b/qbittorrent-web-api-gen/Cargo.toml index 181d229..d76b7b4 100644 --- a/qbittorrent-web-api-gen/Cargo.toml +++ b/qbittorrent-web-api-gen/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT" keywords = ["qbittorrent"] repository = "https://github.com/JoelWachsler/qbittorrent-web-api" description = "Generated web api for qBittorrent" -exclude = ["*.txt", "tests", "qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests"] +exclude = ["*.txt", "tests", "src/md_parser/token_tree_factory_tests"] # we use trybuild instead autotests = false From 250a1d098c70cd66e6fec7b7d74090bc5b41c97a Mon Sep 17 00:00:00 2001 From: Joel Wachsler Date: Thu, 14 Jul 2022 20:50:46 +0000 Subject: [PATCH 12/47] Add abstraction over ApiParameters --- qbittorrent-web-api-gen/groups.txt | 2562 +++++++++-------- .../group/method/method_with_params.rs | 33 +- .../src/parser/group/method/mod.rs | 32 +- .../src/parser/group/mod.rs | 2 +- qbittorrent-web-api-gen/src/parser/mod.rs | 2 +- 5 files changed, 1401 insertions(+), 1230 deletions(-) diff --git a/qbittorrent-web-api-gen/groups.txt b/qbittorrent-web-api-gen/groups.txt index 2d6c67a..e34dc7b 100644 --- a/qbittorrent-web-api-gen/groups.txt +++ b/qbittorrent-web-api-gen/groups.txt @@ -8,30 +8,33 @@ "Upon success, the response will contain a cookie with your SID. You must supply the cookie whenever you want to perform an operation that requires authentication.\n\nExample showing how to login and execute a command that requires authentication using `curl`:\n\n```sh\n$ curl -i --header 'Referer: http://localhost:8080' --data 'username=admin&password=adminadmin' http://localhost:8080/api/v2/auth/login\nHTTP/1.1 200 OK\nContent-Encoding:\nContent-Length: 3\nContent-Type: text/plain; charset=UTF-8\nSet-Cookie: SID=hBc7TxF76ERhvIw0jQQ4LZ7Z1jQUV0tQ; path=/\n$ curl http://localhost:8080/api/v2/torrents/info --cookie \"SID=hBc7TxF76ERhvIw0jQQ4LZ7Z1jQUV0tQ\"\n```\n\nNote: Set `Referer` or `Origin` header to the exact same domain and port as used in the HTTP query `Host` header.", ), parameters: Some( - [ - String( - TypeInfo { - name: "username", - is_optional: false, - is_list: false, - description: Some( - "Username used to access the WebUI", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "password", - is_optional: false, - is_list: false, - description: Some( - "Password used to access the WebUI", - ), - type_description: None, - }, - ), - ], + ApiParameters { + mandatory: [ + String( + TypeInfo { + name: "username", + is_optional: false, + is_list: false, + description: Some( + "Username used to access the WebUI", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "password", + is_optional: false, + is_list: false, + description: Some( + "Password used to access the WebUI", + ), + type_description: None, + }, + ), + ], + optional: [], + }, ), return_type: None, url: "login", @@ -2599,63 +2602,66 @@ "The response is a JSON array in which each element is an entry of the log.\n\nEach element of the array has the following properties:\n\n\nExample:\n\n```JSON\n[\n {\n \"id\":0,\n \"message\":\"qBittorrent v3.4.0 started\",\n \"timestamp\":1507969127860,\n \"type\":1\n },\n {\n \"id\":1,\n \"message\":\"qBittorrent is trying to listen on any interface port: 19036\",\n \"timestamp\":1507969127869,\n \"type\":2\n },\n {\n \"id\":2,\n \"message\":\"Peer ID: -qB3400-\",\n \"timestamp\":1507969127870,\n \"type\":1\n },\n {\n \"id\":3,\n \"message\":\"HTTP User-Agent is 'qBittorrent/3.4.0'\",\n \"timestamp\":1507969127870,\n \"type\":1\n },\n {\n \"id\":4,\n \"message\":\"DHT support [ON]\",\n \"timestamp\":1507969127871,\n \"type\":2\n },\n {\n \"id\":5,\n \"message\":\"Local Peer Discovery support [ON]\",\n \"timestamp\":1507969127871,\n \"type\":2\n },\n {\n \"id\":6,\n \"message\":\"PeX support [ON]\",\n \"timestamp\":1507969127871,\n \"type\":2\n },\n {\n \"id\":7,\n \"message\":\"Anonymous mode [OFF]\",\n \"timestamp\":1507969127871,\n \"type\":2\n },\n {\n \"id\":8,\n \"message\":\"Encryption support [ON]\",\n \"timestamp\":1507969127871,\n \"type\":2\n },\n {\n \"id\":9,\n \"message\":\"Embedded Tracker [OFF]\",\n \"timestamp\":1507969127871,\n \"type\":2\n },\n {\n \"id\":10,\n \"message\":\"UPnP / NAT-PMP support [ON]\",\n \"timestamp\":1507969127873,\n \"type\":2\n },\n {\n \"id\":11,\n \"message\":\"Web UI: Now listening on port 8080\",\n \"timestamp\":1507969127883,\n \"type\":1\n },\n {\n \"id\":12,\n \"message\":\"Options were saved successfully.\",\n \"timestamp\":1507969128055,\n \"type\":1\n },\n {\n \"id\":13,\n \"message\":\"qBittorrent is successfully listening on interface :: port: TCP/19036\",\n \"timestamp\":1507969128270,\n \"type\":2\n },\n {\n \"id\":14,\n \"message\":\"qBittorrent is successfully listening on interface 0.0.0.0 port: TCP/19036\",\n \"timestamp\":1507969128271,\n \"type\":2\n },\n {\n \"id\":15,\n \"message\":\"qBittorrent is successfully listening on interface 0.0.0.0 port: UDP/19036\",\n \"timestamp\":1507969128272,\n \"type\":2\n }\n]\n```", ), parameters: Some( - [ - Bool( - TypeInfo { - name: "normal", - is_optional: true, - is_list: false, - description: Some( - "Include normal messages (default: true)", - ), - type_description: None, - }, - ), - Bool( - TypeInfo { - name: "info", - is_optional: true, - is_list: false, - description: Some( - "Include info messages (default: true)", - ), - type_description: None, - }, - ), - Bool( - TypeInfo { - name: "warning", - is_optional: true, - is_list: false, - description: Some( - "Include warning messages (default: true)", - ), - type_description: None, - }, - ), - Bool( - TypeInfo { - name: "critical", - is_optional: true, - is_list: false, - description: Some( - "Include critical messages (default: true)", - ), - type_description: None, - }, - ), - Number( - TypeInfo { - name: "last_known_id", - is_optional: true, - is_list: false, - description: Some( - "Exclude messages with \"message id\" <= last_known_id (default: -1)", - ), - type_description: None, - }, - ), - ], + ApiParameters { + mandatory: [], + optional: [ + Bool( + TypeInfo { + name: "normal", + is_optional: true, + is_list: false, + description: Some( + "Include normal messages (default: true)", + ), + type_description: None, + }, + ), + Bool( + TypeInfo { + name: "info", + is_optional: true, + is_list: false, + description: Some( + "Include info messages (default: true)", + ), + type_description: None, + }, + ), + Bool( + TypeInfo { + name: "warning", + is_optional: true, + is_list: false, + description: Some( + "Include warning messages (default: true)", + ), + type_description: None, + }, + ), + Bool( + TypeInfo { + name: "critical", + is_optional: true, + is_list: false, + description: Some( + "Include critical messages (default: true)", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "last_known_id", + is_optional: true, + is_list: false, + description: Some( + "Exclude messages with \"message id\" <= last_known_id (default: -1)", + ), + type_description: None, + }, + ), + ], + }, ), return_type: Some( ReturnType { @@ -2732,19 +2738,22 @@ "The response a JSON array. Each element of the array of objects (each object is the information relative to a peer) containing the following fields", ), parameters: Some( - [ - Number( - TypeInfo { - name: "last_known_id", - is_optional: true, - is_list: false, - description: Some( - "Exclude messages with \"message id\" <= last_known_id (default: -1)", - ), - type_description: None, - }, - ), - ], + ApiParameters { + mandatory: [], + optional: [ + Number( + TypeInfo { + name: "last_known_id", + is_optional: true, + is_list: false, + description: Some( + "Exclude messages with \"message id\" <= last_known_id (default: -1)", + ), + type_description: None, + }, + ), + ], + }, ), return_type: None, url: "peers", @@ -2764,19 +2773,22 @@ "The response is a JSON object with the following possible fields\n\n\nExample:\n\n```JSON\n{\n \"rid\":15,\n \"torrents\":\n {\n \"8c212779b4abde7c6bc608063a0d008b7e40ce32\":\n {\n \"state\":\"pausedUP\"\n }\n }\n}\n```", ), parameters: Some( - [ - Number( - TypeInfo { - name: "rid", - is_optional: false, - is_list: false, - description: Some( - "Response ID. If not provided, rid=0 will be assumed. If the given rid is different from the one of last server reply, full_update will be true (see the server reply details for more info)", - ), - type_description: None, - }, - ), - ], + ApiParameters { + mandatory: [ + Number( + TypeInfo { + name: "rid", + is_optional: false, + is_list: false, + description: Some( + "Response ID. If not provided, rid=0 will be assumed. If the given rid is different from the one of last server reply, full_update will be true (see the server reply details for more info)", + ), + type_description: None, + }, + ), + ], + optional: [], + }, ), return_type: Some( ReturnType { @@ -2928,30 +2940,33 @@ "The response is TODO", ), parameters: Some( - [ - String( - TypeInfo { - name: "hash", - is_optional: false, - is_list: false, - description: Some( - "Torrent hash", - ), - type_description: None, - }, - ), - Number( - TypeInfo { - name: "rid", - is_optional: false, - is_list: false, - description: Some( - "Response ID. If not provided, rid=0 will be assumed. If the given rid is different from the one of last server reply, full_update will be true (see the server reply details for more info)", - ), - type_description: None, - }, - ), - ], + ApiParameters { + mandatory: [ + String( + TypeInfo { + name: "hash", + is_optional: false, + is_list: false, + description: Some( + "Torrent hash", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "rid", + is_optional: false, + is_list: false, + description: Some( + "Response ID. If not provided, rid=0 will be assumed. If the given rid is different from the one of last server reply, full_update will be true (see the server reply details for more info)", + ), + type_description: None, + }, + ), + ], + optional: [], + }, ), return_type: None, url: "torrentPeers", @@ -3146,19 +3161,22 @@ name: "setDownloadLimit", description: None, parameters: Some( - [ - Number( - TypeInfo { - name: "limit", - is_optional: false, - is_list: false, - description: Some( - "The global download speed limit to set in bytes/second", - ), - type_description: None, - }, - ), - ], + ApiParameters { + mandatory: [ + Number( + TypeInfo { + name: "limit", + is_optional: false, + is_list: false, + description: Some( + "The global download speed limit to set in bytes/second", + ), + type_description: None, + }, + ), + ], + optional: [], + }, ), return_type: None, url: "setDownloadLimit", @@ -3176,19 +3194,22 @@ name: "setUploadLimit", description: None, parameters: Some( - [ - Number( - TypeInfo { - name: "limit", - is_optional: false, - is_list: false, - description: Some( - "The global upload speed limit to set in bytes/second", - ), - type_description: None, - }, - ), - ], + ApiParameters { + mandatory: [ + Number( + TypeInfo { + name: "limit", + is_optional: false, + is_list: false, + description: Some( + "The global upload speed limit to set in bytes/second", + ), + type_description: None, + }, + ), + ], + optional: [], + }, ), return_type: None, url: "setUploadLimit", @@ -3197,19 +3218,22 @@ name: "banPeers", description: None, parameters: Some( - [ - String( - TypeInfo { - name: "peers", - is_optional: false, - is_list: false, - description: Some( - "The peer to ban, or multiple peers separated by a pipe \\", - ), - type_description: None, - }, - ), - ], + ApiParameters { + mandatory: [ + String( + TypeInfo { + name: "peers", + is_optional: false, + is_list: false, + description: Some( + "The peer to ban, or multiple peers separated by a pipe \\", + ), + type_description: None, + }, + ), + ], + optional: [], + }, ), return_type: None, url: "banPeers", @@ -3229,96 +3253,99 @@ "The response is a JSON array with the following fields\n\n\nPossible values of `state`:\n\n\nExample:\n\n```JSON\n[\n {\n \"dlspeed\":9681262,\n \"eta\":87,\n \"f_l_piece_prio\":false,\n \"force_start\":false,\n \"hash\":\"8c212779b4abde7c6bc608063a0d008b7e40ce32\",\n \"category\":\"\",\n \"tags\": \"\",\n \"name\":\"debian-8.1.0-amd64-CD-1.iso\",\n \"num_complete\":-1,\n \"num_incomplete\":-1,\n \"num_leechs\":2,\n \"num_seeds\":54,\n \"priority\":1,\n \"progress\":0.16108787059783936,\n \"ratio\":0,\n \"seq_dl\":false,\n \"size\":657457152,\n \"state\":\"downloading\",\n \"super_seeding\":false,\n \"upspeed\":0\n },\n {\n another_torrent_info\n }\n]\n```", ), parameters: Some( - [ - String( - TypeInfo { - name: "filter", - is_optional: true, - is_list: false, - description: Some( - "Filter torrent list by state. Allowed state filters: all, downloading, seeding, completed, paused, active, inactive, resumed, stalled, stalled_uploading, stalled_downloading, errored", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "category", - is_optional: true, - is_list: false, - description: Some( - "Get torrents with the given category (empty string means \"without category\"; no \"category\" parameter means \"any category\" <- broken until [#11748](https://github.com/qbittorrent/qBittorrent/issues/11748) is resolved). Remember to URL-encode the category name. For example, My category becomes My%20category", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "tag", - is_optional: true, - is_list: false, - description: Some( - "Get torrents with the given tag (empty string means \"without tag\"; no \"tag\" parameter means \"any tag\". Remember to URL-encode the category name. For example, My tag becomes My%20tag", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "sort", - is_optional: true, - is_list: false, - description: Some( - "Sort torrents by given key. They can be sorted using any field of the response's JSON array (which are documented below) as the sort key.", - ), - type_description: None, - }, - ), - Bool( - TypeInfo { - name: "reverse", - is_optional: true, - is_list: false, - description: Some( - "Enable reverse sorting. Defaults to false", - ), - type_description: None, - }, - ), - Number( - TypeInfo { - name: "limit", - is_optional: true, - is_list: false, - description: Some( - "Limit the number of torrents returned", - ), - type_description: None, - }, - ), - Number( - TypeInfo { - name: "offset", - is_optional: true, - is_list: false, - description: Some( - "Set offset (if less than 0, offset from end)", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "hashes", - is_optional: true, - is_list: false, - description: Some( - "Filter by hashes. Can contain multiple hashes separated by \\", - ), - type_description: None, - }, - ), - ], + ApiParameters { + mandatory: [], + optional: [ + String( + TypeInfo { + name: "filter", + is_optional: true, + is_list: false, + description: Some( + "Filter torrent list by state. Allowed state filters: all, downloading, seeding, completed, paused, active, inactive, resumed, stalled, stalled_uploading, stalled_downloading, errored", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "category", + is_optional: true, + is_list: false, + description: Some( + "Get torrents with the given category (empty string means \"without category\"; no \"category\" parameter means \"any category\" <- broken until [#11748](https://github.com/qbittorrent/qBittorrent/issues/11748) is resolved). Remember to URL-encode the category name. For example, My category becomes My%20category", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "tag", + is_optional: true, + is_list: false, + description: Some( + "Get torrents with the given tag (empty string means \"without tag\"; no \"tag\" parameter means \"any tag\". Remember to URL-encode the category name. For example, My tag becomes My%20tag", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "sort", + is_optional: true, + is_list: false, + description: Some( + "Sort torrents by given key. They can be sorted using any field of the response's JSON array (which are documented below) as the sort key.", + ), + type_description: None, + }, + ), + Bool( + TypeInfo { + name: "reverse", + is_optional: true, + is_list: false, + description: Some( + "Enable reverse sorting. Defaults to false", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "limit", + is_optional: true, + is_list: false, + description: Some( + "Limit the number of torrents returned", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "offset", + is_optional: true, + is_list: false, + description: Some( + "Set offset (if less than 0, offset from end)", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "hashes", + is_optional: true, + is_list: false, + description: Some( + "Filter by hashes. Can contain multiple hashes separated by \\", + ), + type_description: None, + }, + ), + ], + }, ), return_type: Some( ReturnType { @@ -4091,19 +4118,22 @@ "The response is:\n\n- empty, if the torrent hash is invalid\n- otherwise, a JSON object with the following fields\n\n\nNB: `-1` is returned if the type of the property is integer but its value is not known.\n\nExample:\n\n```JSON\n{\n \"addition_date\":1438429165,\n \"comment\":\"\\\"Debian CD from cdimage.debian.org\\\"\",\n \"completion_date\":1438429234,\n \"created_by\":\"\",\n \"creation_date\":1433605214,\n \"dl_limit\":-1,\n \"dl_speed\":0,\n \"dl_speed_avg\":9736015,\n \"eta\":8640000,\n \"last_seen\":1438430354,\n \"nb_connections\":3,\n \"nb_connections_limit\":250,\n \"peers\":1,\n \"peers_total\":89,\n \"piece_size\":524288,\n \"pieces_have\":1254,\n \"pieces_num\":1254,\n \"reannounce\":672,\n \"save_path\":\"/Downloads/debian-8.1.0-amd64-CD-1.iso\",\n \"seeding_time\":1128,\n \"seeds\":1,\n \"seeds_total\":254,\n \"share_ratio\":0.00072121022562178299,\n \"time_elapsed\":1197,\n \"total_downloaded\":681521119,\n \"total_downloaded_session\":681521119,\n \"total_size\":657457152,\n \"total_uploaded\":491520,\n \"total_uploaded_session\":491520,\n \"total_wasted\":23481724,\n \"up_limit\":-1,\n \"up_speed\":0,\n \"up_speed_avg\":410\n}\n```", ), parameters: Some( - [ - String( - TypeInfo { - name: "hash", - is_optional: false, - is_list: false, - description: Some( - "The hash of the torrent you want to get the generic properties of", - ), - type_description: None, - }, - ), - ], + ApiParameters { + mandatory: [ + String( + TypeInfo { + name: "hash", + is_optional: false, + is_list: false, + description: Some( + "The hash of the torrent you want to get the generic properties of", + ), + type_description: None, + }, + ), + ], + optional: [], + }, ), return_type: None, url: "properties", @@ -4114,19 +4144,22 @@ "The response is a JSON array, where each element contains info about one tracker, with the following fields\n\n\nPossible values of `status`:\n\n\nExample:\n\n```JSON\n[\n {\n \"msg\":\"\",\n \"num_peers\":100,\n \"status\":2,\n \"url\":\"http://bttracker.debian.org:6969/announce\"\n },\n {\n another_tracker_info\n }\n]\n```", ), parameters: Some( - [ - String( - TypeInfo { - name: "hash", - is_optional: false, - is_list: false, - description: Some( - "The hash of the torrent you want to get the trackers of", - ), - type_description: None, - }, - ), - ], + ApiParameters { + mandatory: [ + String( + TypeInfo { + name: "hash", + is_optional: false, + is_list: false, + description: Some( + "The hash of the torrent you want to get the trackers of", + ), + type_description: None, + }, + ), + ], + optional: [], + }, ), return_type: Some( ReturnType { @@ -4288,19 +4321,22 @@ "The response is a JSON array, where each element is information about one webseed, with the following fields\n\n\nExample:\n\n```JSON\n[\n {\n \"url\":\"http://some_url/\"\n },\n {\n \"url\":\"http://some_other_url/\"\n }\n]\n```", ), parameters: Some( - [ - String( - TypeInfo { - name: "hash", - is_optional: false, - is_list: false, - description: Some( - "The hash of the torrent you want to get the webseeds of", - ), - type_description: None, - }, - ), - ], + ApiParameters { + mandatory: [ + String( + TypeInfo { + name: "hash", + is_optional: false, + is_list: false, + description: Some( + "The hash of the torrent you want to get the webseeds of", + ), + type_description: None, + }, + ), + ], + optional: [], + }, ), return_type: Some( ReturnType { @@ -4332,30 +4368,34 @@ "The response is:\n\n- empty, if the torrent hash is invalid\n- otherwise, a JSON array, where each element contains info about one file, with the following fields\n\n\nPossible values of `priority`:\n\n\nExample:\n\n```JSON\n\n[\n {\n \"index\":0,\n \"is_seed\":false,\n \"name\":\"debian-8.1.0-amd64-CD-1.iso\",\n \"piece_range\":[0,1253],\n \"priority\":1,\n \"progress\":0,\n \"size\":657457152,\n \"availability\":0.5,\n }\n]\n```", ), parameters: Some( - [ - String( - TypeInfo { - name: "hash", - is_optional: false, - is_list: false, - description: Some( - "The hash of the torrent you want to get the contents of", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "indexes", - is_optional: true, - is_list: false, - description: Some( - "The indexes of the files you want to retrieve. indexes can contain multiple values separated by \\", - ), - type_description: None, - }, - ), - ], + ApiParameters { + mandatory: [ + String( + TypeInfo { + name: "hash", + is_optional: false, + is_list: false, + description: Some( + "The hash of the torrent you want to get the contents of", + ), + type_description: None, + }, + ), + ], + optional: [ + String( + TypeInfo { + name: "indexes", + is_optional: true, + is_list: false, + description: Some( + "The indexes of the files you want to retrieve. indexes can contain multiple values separated by \\", + ), + type_description: None, + }, + ), + ], + }, ), return_type: None, url: "files", @@ -4366,19 +4406,22 @@ "The response is:\n\n- empty, if the torrent hash is invalid\n- otherwise, an array of states (integers) of all pieces (in order) of a specific torrent.\n\nValue meanings are defined as below:\n\n\nExample:\n\n```JSON\n[0,0,2,1,0,0,2,1]\n```", ), parameters: Some( - [ - String( - TypeInfo { - name: "hash", - is_optional: false, - is_list: false, - description: Some( - "The hash of the torrent you want to get the pieces' states of", - ), - type_description: None, - }, - ), - ], + ApiParameters { + mandatory: [ + String( + TypeInfo { + name: "hash", + is_optional: false, + is_list: false, + description: Some( + "The hash of the torrent you want to get the pieces' states of", + ), + type_description: None, + }, + ), + ], + optional: [], + }, ), return_type: None, url: "pieceStates", @@ -4389,19 +4432,22 @@ "The response is:\n\n- empty, if the torrent hash is invalid\n- otherwise, an array of hashes (strings) of all pieces (in order) of a specific torrent.\n\nExample:\n\n```JSON\n[\"54eddd830a5b58480a6143d616a97e3a6c23c439\",\"f8a99d225aa4241db100f88407fc3bdaead583ab\",\"928fb615b9bd4dd8f9e9022552c8f8f37ef76f58\"]\n```", ), parameters: Some( - [ - String( - TypeInfo { - name: "hash", - is_optional: false, - is_list: false, - description: Some( - "The hash of the torrent you want to get the pieces' hashes of", - ), - type_description: None, - }, - ), - ], + ApiParameters { + mandatory: [ + String( + TypeInfo { + name: "hash", + is_optional: false, + is_list: false, + description: Some( + "The hash of the torrent you want to get the pieces' hashes of", + ), + type_description: None, + }, + ), + ], + optional: [], + }, ), return_type: None, url: "pieceHashes", @@ -4410,19 +4456,22 @@ name: "pause", description: None, parameters: Some( - [ - String( - TypeInfo { - name: "hashes", - is_optional: false, - is_list: false, - description: Some( - "The hashes of the torrents you want to pause. hashes can contain multiple hashes separated by \\", - ), - type_description: None, - }, - ), - ], + ApiParameters { + mandatory: [ + String( + TypeInfo { + name: "hashes", + is_optional: false, + is_list: false, + description: Some( + "The hashes of the torrents you want to pause. hashes can contain multiple hashes separated by \\", + ), + type_description: None, + }, + ), + ], + optional: [], + }, ), return_type: None, url: "pause", @@ -4431,19 +4480,22 @@ name: "resume", description: None, parameters: Some( - [ - String( - TypeInfo { - name: "hashes", - is_optional: false, - is_list: false, - description: Some( - "The hashes of the torrents you want to resume. hashes can contain multiple hashes separated by \\", - ), - type_description: None, - }, - ), - ], + ApiParameters { + mandatory: [ + String( + TypeInfo { + name: "hashes", + is_optional: false, + is_list: false, + description: Some( + "The hashes of the torrents you want to resume. hashes can contain multiple hashes separated by \\", + ), + type_description: None, + }, + ), + ], + optional: [], + }, ), return_type: None, url: "resume", @@ -4452,19 +4504,22 @@ name: "delete", description: None, parameters: Some( - [ - String( - TypeInfo { - name: "hashes", - is_optional: false, - is_list: false, - description: Some( - "The hashes of the torrents you want to delete. hashes can contain multiple hashes separated by \\", - ), - type_description: None, - }, - ), - ], + ApiParameters { + mandatory: [ + String( + TypeInfo { + name: "hashes", + is_optional: false, + is_list: false, + description: Some( + "The hashes of the torrents you want to delete. hashes can contain multiple hashes separated by \\", + ), + type_description: None, + }, + ), + ], + optional: [], + }, ), return_type: None, url: "delete", @@ -4473,19 +4528,22 @@ name: "recheck", description: None, parameters: Some( - [ - String( - TypeInfo { - name: "hashes", - is_optional: false, - is_list: false, - description: Some( - "The hashes of the torrents you want to recheck. hashes can contain multiple hashes separated by \\", - ), - type_description: None, - }, - ), - ], + ApiParameters { + mandatory: [ + String( + TypeInfo { + name: "hashes", + is_optional: false, + is_list: false, + description: Some( + "The hashes of the torrents you want to recheck. hashes can contain multiple hashes separated by \\", + ), + type_description: None, + }, + ), + ], + optional: [], + }, ), return_type: None, url: "recheck", @@ -4494,19 +4552,22 @@ name: "reannounce", description: None, parameters: Some( - [ - String( - TypeInfo { - name: "hashes", - is_optional: false, - is_list: false, - description: Some( - "The hashes of the torrents you want to reannounce. hashes can contain multiple hashes separated by \\", - ), - type_description: None, - }, - ), - ], + ApiParameters { + mandatory: [ + String( + TypeInfo { + name: "hashes", + is_optional: false, + is_list: false, + description: Some( + "The hashes of the torrents you want to reannounce. hashes can contain multiple hashes separated by \\", + ), + type_description: None, + }, + ), + ], + optional: [], + }, ), return_type: None, url: "reannounce", @@ -4515,184 +4576,188 @@ name: "add", description: None, parameters: Some( - [ - String( - TypeInfo { - name: "urls", - is_optional: false, - is_list: false, - description: Some( - "URLs separated with newlines", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "savepath", - is_optional: true, - is_list: false, - description: Some( - "Download folder", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "cookie", - is_optional: true, - is_list: false, - description: Some( - "Cookie sent to download the .torrent file", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "category", - is_optional: true, - is_list: false, - description: Some( - "Category for the torrent", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "tags", - is_optional: true, - is_list: false, - description: Some( - "Tags for the torrent, split by ','", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "skip_checking", - is_optional: true, - is_list: false, - description: Some( - "Skip hash checking. Possible values are true, false (default)", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "paused", - is_optional: true, - is_list: false, - description: Some( - "Add torrents in the paused state. Possible values are true, false (default)", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "root_folder", - is_optional: true, - is_list: false, - description: Some( - "Create the root folder. Possible values are true, false, unset (default)", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "rename", - is_optional: true, - is_list: false, - description: Some( - "Rename torrent", - ), - type_description: None, - }, - ), - Number( - TypeInfo { - name: "upLimit", - is_optional: true, - is_list: false, - description: Some( - "Set torrent upload speed limit. Unit in bytes/second", - ), - type_description: None, - }, - ), - Number( - TypeInfo { - name: "dlLimit", - is_optional: true, - is_list: false, - description: Some( - "Set torrent download speed limit. Unit in bytes/second", - ), - type_description: None, - }, - ), - Float( - TypeInfo { - name: "ratioLimit", - is_optional: true, - is_list: false, - description: Some( - "Set torrent share ratio limit", - ), - type_description: None, - }, - ), - Number( - TypeInfo { - name: "seedingTimeLimit", - is_optional: true, - is_list: false, - description: Some( - "Set torrent seeding time limit. Unit in seconds", - ), - type_description: None, - }, - ), - Bool( - TypeInfo { - name: "autoTMM", - is_optional: true, - is_list: false, - description: Some( - "Whether Automatic Torrent Management should be used", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "sequentialDownload", - is_optional: true, - is_list: false, - description: Some( - "Enable sequential download. Possible values are true, false (default)", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "firstLastPiecePrio", - is_optional: true, - is_list: false, - description: Some( - "Prioritize download first last piece. Possible values are true, false (default)", - ), - type_description: None, - }, - ), - ], + ApiParameters { + mandatory: [ + String( + TypeInfo { + name: "urls", + is_optional: false, + is_list: false, + description: Some( + "URLs separated with newlines", + ), + type_description: None, + }, + ), + ], + optional: [ + String( + TypeInfo { + name: "savepath", + is_optional: true, + is_list: false, + description: Some( + "Download folder", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "cookie", + is_optional: true, + is_list: false, + description: Some( + "Cookie sent to download the .torrent file", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "category", + is_optional: true, + is_list: false, + description: Some( + "Category for the torrent", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "tags", + is_optional: true, + is_list: false, + description: Some( + "Tags for the torrent, split by ','", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "skip_checking", + is_optional: true, + is_list: false, + description: Some( + "Skip hash checking. Possible values are true, false (default)", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "paused", + is_optional: true, + is_list: false, + description: Some( + "Add torrents in the paused state. Possible values are true, false (default)", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "root_folder", + is_optional: true, + is_list: false, + description: Some( + "Create the root folder. Possible values are true, false, unset (default)", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "rename", + is_optional: true, + is_list: false, + description: Some( + "Rename torrent", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "upLimit", + is_optional: true, + is_list: false, + description: Some( + "Set torrent upload speed limit. Unit in bytes/second", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "dlLimit", + is_optional: true, + is_list: false, + description: Some( + "Set torrent download speed limit. Unit in bytes/second", + ), + type_description: None, + }, + ), + Float( + TypeInfo { + name: "ratioLimit", + is_optional: true, + is_list: false, + description: Some( + "Set torrent share ratio limit", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "seedingTimeLimit", + is_optional: true, + is_list: false, + description: Some( + "Set torrent seeding time limit. Unit in seconds", + ), + type_description: None, + }, + ), + Bool( + TypeInfo { + name: "autoTMM", + is_optional: true, + is_list: false, + description: Some( + "Whether Automatic Torrent Management should be used", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "sequentialDownload", + is_optional: true, + is_list: false, + description: Some( + "Enable sequential download. Possible values are true, false (default)", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "firstLastPiecePrio", + is_optional: true, + is_list: false, + description: Some( + "Prioritize download first last piece. Possible values are true, false (default)", + ), + type_description: None, + }, + ), + ], + }, ), return_type: None, url: "add", @@ -4708,41 +4773,44 @@ name: "editTracker", description: None, parameters: Some( - [ - String( - TypeInfo { - name: "hash", - is_optional: false, - is_list: false, - description: Some( - "The hash of the torrent", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "origUrl", - is_optional: false, - is_list: false, - description: Some( - "The tracker URL you want to edit", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "newUrl", - is_optional: false, - is_list: false, - description: Some( - "The new URL to replace the origUrl", - ), - type_description: None, - }, - ), - ], + ApiParameters { + mandatory: [ + String( + TypeInfo { + name: "hash", + is_optional: false, + is_list: false, + description: Some( + "The hash of the torrent", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "origUrl", + is_optional: false, + is_list: false, + description: Some( + "The tracker URL you want to edit", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "newUrl", + is_optional: false, + is_list: false, + description: Some( + "The new URL to replace the origUrl", + ), + type_description: None, + }, + ), + ], + optional: [], + }, ), return_type: None, url: "editTracker", @@ -4751,30 +4819,33 @@ name: "removeTrackers", description: None, parameters: Some( - [ - String( - TypeInfo { - name: "hash", - is_optional: false, - is_list: false, - description: Some( - "The hash of the torrent", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "urls", - is_optional: false, - is_list: false, - description: Some( - "URLs to remove, separated by \\", - ), - type_description: None, - }, - ), - ], + ApiParameters { + mandatory: [ + String( + TypeInfo { + name: "hash", + is_optional: false, + is_list: false, + description: Some( + "The hash of the torrent", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "urls", + is_optional: false, + is_list: false, + description: Some( + "URLs to remove, separated by \\", + ), + type_description: None, + }, + ), + ], + optional: [], + }, ), return_type: None, url: "removeTrackers", @@ -4783,30 +4854,33 @@ name: "addPeers", description: None, parameters: Some( - [ - String( - TypeInfo { - name: "hashes", - is_optional: false, - is_list: false, - description: Some( - "The hash of the torrent, or multiple hashes separated by a pipe \\", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "peers", - is_optional: false, - is_list: false, - description: Some( - "The peer to add, or multiple peers separated by a pipe \\", - ), - type_description: None, - }, - ), - ], + ApiParameters { + mandatory: [ + String( + TypeInfo { + name: "hashes", + is_optional: false, + is_list: false, + description: Some( + "The hash of the torrent, or multiple hashes separated by a pipe \\", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "peers", + is_optional: false, + is_list: false, + description: Some( + "The peer to add, or multiple peers separated by a pipe \\", + ), + type_description: None, + }, + ), + ], + optional: [], + }, ), return_type: None, url: "addPeers", @@ -4815,19 +4889,22 @@ name: "increasePrio", description: None, parameters: Some( - [ - String( - TypeInfo { - name: "hashes", - is_optional: false, - is_list: false, - description: Some( - "The hashes of the torrents you want to increase the priority of. hashes can contain multiple hashes separated by \\", - ), - type_description: None, - }, - ), - ], + ApiParameters { + mandatory: [ + String( + TypeInfo { + name: "hashes", + is_optional: false, + is_list: false, + description: Some( + "The hashes of the torrents you want to increase the priority of. hashes can contain multiple hashes separated by \\", + ), + type_description: None, + }, + ), + ], + optional: [], + }, ), return_type: None, url: "increasePrio", @@ -4836,19 +4913,22 @@ name: "decreasePrio", description: None, parameters: Some( - [ - String( - TypeInfo { - name: "hashes", - is_optional: false, - is_list: false, - description: Some( - "The hashes of the torrents you want to decrease the priority of. hashes can contain multiple hashes separated by \\", - ), - type_description: None, - }, - ), - ], + ApiParameters { + mandatory: [ + String( + TypeInfo { + name: "hashes", + is_optional: false, + is_list: false, + description: Some( + "The hashes of the torrents you want to decrease the priority of. hashes can contain multiple hashes separated by \\", + ), + type_description: None, + }, + ), + ], + optional: [], + }, ), return_type: None, url: "decreasePrio", @@ -4857,19 +4937,22 @@ name: "topPrio", description: None, parameters: Some( - [ - String( - TypeInfo { - name: "hashes", - is_optional: false, - is_list: false, - description: Some( - "The hashes of the torrents you want to set to the maximum priority. hashes can contain multiple hashes separated by \\", - ), - type_description: None, - }, - ), - ], + ApiParameters { + mandatory: [ + String( + TypeInfo { + name: "hashes", + is_optional: false, + is_list: false, + description: Some( + "The hashes of the torrents you want to set to the maximum priority. hashes can contain multiple hashes separated by \\", + ), + type_description: None, + }, + ), + ], + optional: [], + }, ), return_type: None, url: "topPrio", @@ -4878,19 +4961,22 @@ name: "bottomPrio", description: None, parameters: Some( - [ - String( - TypeInfo { - name: "hashes", - is_optional: false, - is_list: false, - description: Some( - "The hashes of the torrents you want to set to the minimum priority. hashes can contain multiple hashes separated by \\", - ), - type_description: None, - }, - ), - ], + ApiParameters { + mandatory: [ + String( + TypeInfo { + name: "hashes", + is_optional: false, + is_list: false, + description: Some( + "The hashes of the torrents you want to set to the minimum priority. hashes can contain multiple hashes separated by \\", + ), + type_description: None, + }, + ), + ], + optional: [], + }, ), return_type: None, url: "bottomPrio", @@ -4899,41 +4985,44 @@ name: "filePrio", description: None, parameters: Some( - [ - String( - TypeInfo { - name: "hash", - is_optional: false, - is_list: false, - description: Some( - "The hash of the torrent", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "id", - is_optional: false, - is_list: false, - description: Some( - "File ids, separated by \\", - ), - type_description: None, - }, - ), - Number( - TypeInfo { - name: "priority", - is_optional: false, - is_list: false, - description: Some( - "File priority to set (consult [torrent contents API](#get-torrent-contents) for possible values)", - ), - type_description: None, - }, - ), - ], + ApiParameters { + mandatory: [ + String( + TypeInfo { + name: "hash", + is_optional: false, + is_list: false, + description: Some( + "The hash of the torrent", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "id", + is_optional: false, + is_list: false, + description: Some( + "File ids, separated by \\", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "priority", + is_optional: false, + is_list: false, + description: Some( + "File priority to set (consult [torrent contents API](#get-torrent-contents) for possible values)", + ), + type_description: None, + }, + ), + ], + optional: [], + }, ), return_type: None, url: "filePrio", @@ -5061,19 +5150,22 @@ name: "toggleSequentialDownload", description: None, parameters: Some( - [ - String( - TypeInfo { - name: "hashes", - is_optional: false, - is_list: false, - description: Some( - "The hashes of the torrents you want to toggle sequential download for. hashes can contain multiple hashes separated by \\", - ), - type_description: None, - }, - ), - ], + ApiParameters { + mandatory: [ + String( + TypeInfo { + name: "hashes", + is_optional: false, + is_list: false, + description: Some( + "The hashes of the torrents you want to toggle sequential download for. hashes can contain multiple hashes separated by \\", + ), + type_description: None, + }, + ), + ], + optional: [], + }, ), return_type: None, url: "toggleSequentialDownload", @@ -5082,19 +5174,22 @@ name: "toggleFirstLastPiecePrio", description: None, parameters: Some( - [ - String( - TypeInfo { - name: "hashes", - is_optional: false, - is_list: false, - description: Some( - "The hashes of the torrents you want to toggle the first/last piece priority for. hashes can contain multiple hashes separated by \\", - ), - type_description: None, - }, - ), - ], + ApiParameters { + mandatory: [ + String( + TypeInfo { + name: "hashes", + is_optional: false, + is_list: false, + description: Some( + "The hashes of the torrents you want to toggle the first/last piece priority for. hashes can contain multiple hashes separated by \\", + ), + type_description: None, + }, + ), + ], + optional: [], + }, ), return_type: None, url: "toggleFirstLastPiecePrio", @@ -5117,41 +5212,44 @@ name: "renameFile", description: None, parameters: Some( - [ - String( - TypeInfo { - name: "hash", - is_optional: false, - is_list: false, - description: Some( - "The hash of the torrent", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "oldPath", - is_optional: false, - is_list: false, - description: Some( - "The old path of the torrent", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "newPath", - is_optional: false, - is_list: false, - description: Some( - "The new path to use for the file", - ), - type_description: None, - }, - ), - ], + ApiParameters { + mandatory: [ + String( + TypeInfo { + name: "hash", + is_optional: false, + is_list: false, + description: Some( + "The hash of the torrent", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "oldPath", + is_optional: false, + is_list: false, + description: Some( + "The old path of the torrent", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "newPath", + is_optional: false, + is_list: false, + description: Some( + "The new path to use for the file", + ), + type_description: None, + }, + ), + ], + optional: [], + }, ), return_type: None, url: "renameFile", @@ -5160,41 +5258,44 @@ name: "renameFolder", description: None, parameters: Some( - [ - String( - TypeInfo { - name: "hash", - is_optional: false, - is_list: false, - description: Some( - "The hash of the torrent", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "oldPath", - is_optional: false, - is_list: false, - description: Some( - "The old path of the torrent", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "newPath", - is_optional: false, - is_list: false, - description: Some( - "The new path to use for the file", - ), - type_description: None, - }, - ), - ], + ApiParameters { + mandatory: [ + String( + TypeInfo { + name: "hash", + is_optional: false, + is_list: false, + description: Some( + "The hash of the torrent", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "oldPath", + is_optional: false, + is_list: false, + description: Some( + "The old path of the torrent", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "newPath", + is_optional: false, + is_list: false, + description: Some( + "The new path to use for the file", + ), + type_description: None, + }, + ), + ], + optional: [], + }, ), return_type: None, url: "renameFolder", @@ -5212,19 +5313,22 @@ name: "addFolder", description: None, parameters: Some( - [ - String( - TypeInfo { - name: "path", - is_optional: false, - is_list: false, - description: Some( - "Full path of added folder (e.g. \"The Pirate Bay\\Top100\")", - ), - type_description: None, - }, - ), - ], + ApiParameters { + mandatory: [ + String( + TypeInfo { + name: "path", + is_optional: false, + is_list: false, + description: Some( + "Full path of added folder (e.g. \"The Pirate Bay\\Top100\")", + ), + type_description: None, + }, + ), + ], + optional: [], + }, ), return_type: None, url: "addFolder", @@ -5233,30 +5337,34 @@ name: "addFeed", description: None, parameters: Some( - [ - String( - TypeInfo { - name: "url", - is_optional: false, - is_list: false, - description: Some( - "URL of RSS feed (e.g. \"[http://thepiratebay.org/rss//top100/200](http://thepiratebay.org/rss//top100/200)\")", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "path", - is_optional: true, - is_list: false, - description: Some( - "Full path of added folder (e.g. \"The Pirate Bay\\Top100\\Video\")", - ), - type_description: None, - }, - ), - ], + ApiParameters { + mandatory: [ + String( + TypeInfo { + name: "url", + is_optional: false, + is_list: false, + description: Some( + "URL of RSS feed (e.g. \"[http://thepiratebay.org/rss//top100/200](http://thepiratebay.org/rss//top100/200)\")", + ), + type_description: None, + }, + ), + ], + optional: [ + String( + TypeInfo { + name: "path", + is_optional: true, + is_list: false, + description: Some( + "Full path of added folder (e.g. \"The Pirate Bay\\Top100\\Video\")", + ), + type_description: None, + }, + ), + ], + }, ), return_type: None, url: "addFeed", @@ -5265,19 +5373,22 @@ name: "removeItem", description: None, parameters: Some( - [ - String( - TypeInfo { - name: "path", - is_optional: false, - is_list: false, - description: Some( - "Full path of removed item (e.g. \"The Pirate Bay\\Top100\")", - ), - type_description: None, - }, - ), - ], + ApiParameters { + mandatory: [ + String( + TypeInfo { + name: "path", + is_optional: false, + is_list: false, + description: Some( + "Full path of removed item (e.g. \"The Pirate Bay\\Top100\")", + ), + type_description: None, + }, + ), + ], + optional: [], + }, ), return_type: None, url: "removeItem", @@ -5286,30 +5397,33 @@ name: "moveItem", description: None, parameters: Some( - [ - String( - TypeInfo { - name: "itemPath", - is_optional: false, - is_list: false, - description: Some( - "Current full path of item (e.g. \"The Pirate Bay\\Top100\")", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "destPath", - is_optional: false, - is_list: false, - description: Some( - "New full path of item (e.g. \"The Pirate Bay\")", - ), - type_description: None, - }, - ), - ], + ApiParameters { + mandatory: [ + String( + TypeInfo { + name: "itemPath", + is_optional: false, + is_list: false, + description: Some( + "Current full path of item (e.g. \"The Pirate Bay\\Top100\")", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "destPath", + is_optional: false, + is_list: false, + description: Some( + "New full path of item (e.g. \"The Pirate Bay\")", + ), + type_description: None, + }, + ), + ], + optional: [], + }, ), return_type: None, url: "moveItem", @@ -5318,19 +5432,22 @@ name: "items", description: None, parameters: Some( - [ - Bool( - TypeInfo { - name: "withData", - is_optional: true, - is_list: false, - description: Some( - "True if you need current feed articles", - ), - type_description: None, - }, - ), - ], + ApiParameters { + mandatory: [], + optional: [ + Bool( + TypeInfo { + name: "withData", + is_optional: true, + is_list: false, + description: Some( + "True if you need current feed articles", + ), + type_description: None, + }, + ), + ], + }, ), return_type: None, url: "items", @@ -5339,30 +5456,34 @@ name: "markAsRead", description: None, parameters: Some( - [ - String( - TypeInfo { - name: "itemPath", - is_optional: false, - is_list: false, - description: Some( - "Current full path of item (e.g. \"The Pirate Bay\\Top100\")", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "articleId", - is_optional: true, - is_list: false, - description: Some( - "ID of article", - ), - type_description: None, - }, - ), - ], + ApiParameters { + mandatory: [ + String( + TypeInfo { + name: "itemPath", + is_optional: false, + is_list: false, + description: Some( + "Current full path of item (e.g. \"The Pirate Bay\\Top100\")", + ), + type_description: None, + }, + ), + ], + optional: [ + String( + TypeInfo { + name: "articleId", + is_optional: true, + is_list: false, + description: Some( + "ID of article", + ), + type_description: None, + }, + ), + ], + }, ), return_type: None, url: "markAsRead", @@ -5371,19 +5492,22 @@ name: "refreshItem", description: None, parameters: Some( - [ - String( - TypeInfo { - name: "itemPath", - is_optional: false, - is_list: false, - description: Some( - "Current full path of item (e.g. \"The Pirate Bay\\Top100\")", - ), - type_description: None, - }, - ), - ], + ApiParameters { + mandatory: [ + String( + TypeInfo { + name: "itemPath", + is_optional: false, + is_list: false, + description: Some( + "Current full path of item (e.g. \"The Pirate Bay\\Top100\")", + ), + type_description: None, + }, + ), + ], + optional: [], + }, ), return_type: None, url: "refreshItem", @@ -5392,30 +5516,33 @@ name: "setRule", description: None, parameters: Some( - [ - String( - TypeInfo { - name: "ruleName", - is_optional: false, - is_list: false, - description: Some( - "Rule name (e.g. \"Punisher\")", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "ruleDef", - is_optional: false, - is_list: false, - description: Some( - "JSON encoded rule definition", - ), - type_description: None, - }, - ), - ], + ApiParameters { + mandatory: [ + String( + TypeInfo { + name: "ruleName", + is_optional: false, + is_list: false, + description: Some( + "Rule name (e.g. \"Punisher\")", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "ruleDef", + is_optional: false, + is_list: false, + description: Some( + "JSON encoded rule definition", + ), + type_description: None, + }, + ), + ], + optional: [], + }, ), return_type: None, url: "setRule", @@ -5424,30 +5551,33 @@ name: "renameRule", description: None, parameters: Some( - [ - String( - TypeInfo { - name: "ruleName", - is_optional: false, - is_list: false, - description: Some( - "Rule name (e.g. \"Punisher\")", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "newRuleName", - is_optional: false, - is_list: false, - description: Some( - "New rule name (e.g. \"The Punisher\")", - ), - type_description: None, - }, - ), - ], + ApiParameters { + mandatory: [ + String( + TypeInfo { + name: "ruleName", + is_optional: false, + is_list: false, + description: Some( + "Rule name (e.g. \"Punisher\")", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "newRuleName", + is_optional: false, + is_list: false, + description: Some( + "New rule name (e.g. \"The Punisher\")", + ), + type_description: None, + }, + ), + ], + optional: [], + }, ), return_type: None, url: "renameRule", @@ -5456,19 +5586,22 @@ name: "removeRule", description: None, parameters: Some( - [ - String( - TypeInfo { - name: "ruleName", - is_optional: false, - is_list: false, - description: Some( - "Rule name (e.g. \"Punisher\")", - ), - type_description: None, - }, - ), - ], + ApiParameters { + mandatory: [ + String( + TypeInfo { + name: "ruleName", + is_optional: false, + is_list: false, + description: Some( + "Rule name (e.g. \"Punisher\")", + ), + type_description: None, + }, + ), + ], + optional: [], + }, ), return_type: None, url: "removeRule", @@ -5502,41 +5635,44 @@ "The response is a JSON object with the following fields\n\n\nExample:\n\n```JSON\n{\n \"id\": 12345\n}\n```", ), parameters: Some( - [ - String( - TypeInfo { - name: "pattern", - is_optional: false, - is_list: false, - description: Some( - "Pattern to search for (e.g. \"Ubuntu 18.04\")", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "plugins", - is_optional: false, - is_list: false, - description: Some( - "Plugins to use for searching (e.g. \"legittorrents\"). Supports multiple plugins separated by \\", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "category", - is_optional: false, - is_list: false, - description: Some( - "Categories to limit your search to (e.g. \"legittorrents\"). Available categories depend on the specified plugins. Also supports all", - ), - type_description: None, - }, - ), - ], + ApiParameters { + mandatory: [ + String( + TypeInfo { + name: "pattern", + is_optional: false, + is_list: false, + description: Some( + "Pattern to search for (e.g. \"Ubuntu 18.04\")", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "plugins", + is_optional: false, + is_list: false, + description: Some( + "Plugins to use for searching (e.g. \"legittorrents\"). Supports multiple plugins separated by \\", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "category", + is_optional: false, + is_list: false, + description: Some( + "Categories to limit your search to (e.g. \"legittorrents\"). Available categories depend on the specified plugins. Also supports all", + ), + type_description: None, + }, + ), + ], + optional: [], + }, ), return_type: Some( ReturnType { @@ -5566,19 +5702,22 @@ name: "stop", description: None, parameters: Some( - [ - Number( - TypeInfo { - name: "id", - is_optional: false, - is_list: false, - description: Some( - "ID of the search job", - ), - type_description: None, - }, - ), - ], + ApiParameters { + mandatory: [ + Number( + TypeInfo { + name: "id", + is_optional: false, + is_list: false, + description: Some( + "ID of the search job", + ), + type_description: None, + }, + ), + ], + optional: [], + }, ), return_type: None, url: "stop", @@ -5589,19 +5728,22 @@ "The response is a JSON array of objects containing the following fields\n\n\nExample:\n\n```JSON\n[\n {\n \"id\": 12345,\n \"status\": \"Running\",\n \"total\": 170\n }\n]\n```", ), parameters: Some( - [ - Number( - TypeInfo { - name: "id", - is_optional: true, - is_list: false, - description: Some( - "ID of the search job. If not specified, all search jobs are returned", - ), - type_description: None, - }, - ), - ], + ApiParameters { + mandatory: [], + optional: [ + Number( + TypeInfo { + name: "id", + is_optional: true, + is_list: false, + description: Some( + "ID of the search job. If not specified, all search jobs are returned", + ), + type_description: None, + }, + ), + ], + }, ), return_type: Some( ReturnType { @@ -5663,41 +5805,45 @@ "The response is a JSON object with the following fields\n\n\n\n\nExample:\n\n```JSON\n{\n \"results\": [\n {\n \"descrLink\": \"http://www.legittorrents.info/index.php?page=torrent-details&id=8d5f512e1acb687029b8d7cc6c5a84dce51d7a41\",\n \"fileName\": \"Ubuntu-10.04-32bit-NeTV.ova\",\n \"fileSize\": -1,\n \"fileUrl\": \"http://www.legittorrents.info/download.php?id=8d5f512e1acb687029b8d7cc6c5a84dce51d7a41&f=Ubuntu-10.04-32bit-NeTV.ova.torrent\",\n \"nbLeechers\": 1,\n \"nbSeeders\": 0,\n \"siteUrl\": \"http://www.legittorrents.info\"\n },\n {\n \"descrLink\": \"http://www.legittorrents.info/index.php?page=torrent-details&id=d5179f53e105dc2c2401bcfaa0c2c4936a6aa475\",\n \"fileName\": \"mangOH-Legato-17_06-Ubuntu-16_04.ova\",\n \"fileSize\": -1,\n \"fileUrl\": \"http://www.legittorrents.info/download.php?id=d5179f53e105dc2c2401bcfaa0c2c4936a6aa475&f=mangOH-Legato-17_06-Ubuntu-16_04.ova.torrent\",\n \"nbLeechers\": 0,\n \"nbSeeders\": 59,\n \"siteUrl\": \"http://www.legittorrents.info\"\n }\n ],\n \"status\": \"Running\",\n \"total\": 2\n}\n```", ), parameters: Some( - [ - Number( - TypeInfo { - name: "id", - is_optional: false, - is_list: false, - description: Some( - "ID of the search job", - ), - type_description: None, - }, - ), - Number( - TypeInfo { - name: "limit", - is_optional: true, - is_list: false, - description: Some( - "max number of results to return. 0 or negative means no limit", - ), - type_description: None, - }, - ), - Number( - TypeInfo { - name: "offset", - is_optional: true, - is_list: false, - description: Some( - "result to start at. A negative number means count backwards (e.g. -2 returns the 2 most recent results)", - ), - type_description: None, - }, - ), - ], + ApiParameters { + mandatory: [ + Number( + TypeInfo { + name: "id", + is_optional: false, + is_list: false, + description: Some( + "ID of the search job", + ), + type_description: None, + }, + ), + ], + optional: [ + Number( + TypeInfo { + name: "limit", + is_optional: true, + is_list: false, + description: Some( + "max number of results to return. 0 or negative means no limit", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "offset", + is_optional: true, + is_list: false, + description: Some( + "result to start at. A negative number means count backwards (e.g. -2 returns the 2 most recent results)", + ), + type_description: None, + }, + ), + ], + }, ), return_type: Some( ReturnType { @@ -5757,19 +5903,22 @@ name: "delete", description: None, parameters: Some( - [ - Number( - TypeInfo { - name: "id", - is_optional: false, - is_list: false, - description: Some( - "ID of the search job", - ), - type_description: None, - }, - ), - ], + ApiParameters { + mandatory: [ + Number( + TypeInfo { + name: "id", + is_optional: false, + is_list: false, + description: Some( + "ID of the search job", + ), + type_description: None, + }, + ), + ], + optional: [], + }, ), return_type: None, url: "delete", @@ -5883,19 +6032,22 @@ name: "installPlugin", description: None, parameters: Some( - [ - String( - TypeInfo { - name: "sources", - is_optional: false, - is_list: false, - description: Some( - "Url or file path of the plugin to install (e.g. \"[https://raw.githubusercontent.com/qbittorrent/search-plugins/master/nova3/engines/legittorrents.py](https://raw.githubusercontent.com/qbittorrent/search-plugins/master/nova3/engines/legittorrents.py)\"). Supports multiple sources separated by \\", - ), - type_description: None, - }, - ), - ], + ApiParameters { + mandatory: [ + String( + TypeInfo { + name: "sources", + is_optional: false, + is_list: false, + description: Some( + "Url or file path of the plugin to install (e.g. \"[https://raw.githubusercontent.com/qbittorrent/search-plugins/master/nova3/engines/legittorrents.py](https://raw.githubusercontent.com/qbittorrent/search-plugins/master/nova3/engines/legittorrents.py)\"). Supports multiple sources separated by \\", + ), + type_description: None, + }, + ), + ], + optional: [], + }, ), return_type: None, url: "installPlugin", @@ -5904,19 +6056,22 @@ name: "uninstallPlugin", description: None, parameters: Some( - [ - String( - TypeInfo { - name: "names", - is_optional: false, - is_list: false, - description: Some( - "Name of the plugin to uninstall (e.g. \"legittorrents\"). Supports multiple names separated by \\", - ), - type_description: None, - }, - ), - ], + ApiParameters { + mandatory: [ + String( + TypeInfo { + name: "names", + is_optional: false, + is_list: false, + description: Some( + "Name of the plugin to uninstall (e.g. \"legittorrents\"). Supports multiple names separated by \\", + ), + type_description: None, + }, + ), + ], + optional: [], + }, ), return_type: None, url: "uninstallPlugin", @@ -5925,30 +6080,33 @@ name: "enablePlugin", description: None, parameters: Some( - [ - String( - TypeInfo { - name: "names", - is_optional: false, - is_list: false, - description: Some( - "Name of the plugin to enable/disable (e.g. \"legittorrents\"). Supports multiple names separated by \\", - ), - type_description: None, - }, - ), - Bool( - TypeInfo { - name: "enable", - is_optional: false, - is_list: false, - description: Some( - "Whether the plugins should be enabled", - ), - type_description: None, - }, - ), - ], + ApiParameters { + mandatory: [ + String( + TypeInfo { + name: "names", + is_optional: false, + is_list: false, + description: Some( + "Name of the plugin to enable/disable (e.g. \"legittorrents\"). Supports multiple names separated by \\", + ), + type_description: None, + }, + ), + Bool( + TypeInfo { + name: "enable", + is_optional: false, + is_list: false, + description: Some( + "Whether the plugins should be enabled", + ), + type_description: None, + }, + ), + ], + optional: [], + }, ), return_type: None, url: "enablePlugin", diff --git a/qbittorrent-web-api-gen/src/generate/group/method/method_with_params.rs b/qbittorrent-web-api-gen/src/generate/group/method/method_with_params.rs index 5af6ef0..a25e844 100644 --- a/qbittorrent-web-api-gen/src/generate/group/method/method_with_params.rs +++ b/qbittorrent-web-api-gen/src/generate/group/method/method_with_params.rs @@ -8,7 +8,7 @@ use super::{return_type::create_return_type, send_method_builder::SendMethodBuil pub fn create_method_with_params( group: &parser::ApiGroup, method: &parser::ApiMethod, - params: &[types::Type], + params: &parser::ApiParameters, method_name: &proc_macro2::Ident, url: &str, ) -> (proc_macro2::TokenStream, Option) { @@ -18,10 +18,9 @@ pub fn create_method_with_params( method.name.to_camel() )); - let mandatory_params = mandatory_params(params); - let mandatory_param_args = generate_mandatory_params(&mandatory_params); + let mandatory_param_args = generate_mandatory_params(¶ms.mandatory); - let mandatory_param_names = mandatory_params.iter().map(|param| { + let mandatory_param_names = params.mandatory.iter().map(|param| { let (name, ..) = param_name(param); quote! { #name } }); @@ -32,8 +31,8 @@ pub fn create_method_with_params( .with_form(); let generate_send_impl = |send_method: proc_macro2::TokenStream| { - let optional_params = generate_optional_params(params); - let mandatory_param_form_build = generate_mandatory_param_builder(&mandatory_params); + let optional_params = generate_optional_params(¶ms.optional); + let mandatory_param_form_build = generate_mandatory_param_builder(¶ms.mandatory); quote! { impl<'a> #param_type<'a> { @@ -82,15 +81,12 @@ pub fn create_method_with_params( (builder, Some(group_impl)) } -fn generate_mandatory_params(mandatory_params: &[&types::Type]) -> Vec { - mandatory_params - .iter() - .map(|param| param_with_name(param)) - .collect() +fn generate_mandatory_params(mandatory_params: &[types::Type]) -> Vec { + mandatory_params.iter().map(param_with_name).collect() } fn generate_mandatory_param_builder( - mandatory_params: &[&types::Type], + mandatory_params: &[types::Type], ) -> Vec { mandatory_params .iter() @@ -102,18 +98,7 @@ fn generate_mandatory_param_builder( } fn generate_optional_params(params: &[types::Type]) -> Vec { - params - .iter() - .filter(|param| param.get_type_info().is_optional) - .map(generate_optional_param) - .collect() -} - -fn mandatory_params(params: &[types::Type]) -> Vec<&types::Type> { - params - .iter() - .filter(|param| !param.get_type_info().is_optional) - .collect() + params.iter().map(generate_optional_param).collect() } fn generate_optional_param(param: &types::Type) -> proc_macro2::TokenStream { diff --git a/qbittorrent-web-api-gen/src/parser/group/method/mod.rs b/qbittorrent-web-api-gen/src/parser/group/method/mod.rs index 3d374f8..64a154d 100644 --- a/qbittorrent-web-api-gen/src/parser/group/method/mod.rs +++ b/qbittorrent-web-api-gen/src/parser/group/method/mod.rs @@ -16,11 +16,39 @@ use self::{ pub struct ApiMethod { pub name: String, pub description: Option, - pub parameters: Option>, + pub parameters: Option, pub return_type: Option, pub url: String, } +#[derive(Debug)] +pub struct ApiParameters { + pub mandatory: Vec, + pub optional: Vec, +} + +impl ApiParameters { + fn new(params: Vec) -> Self { + let (mandatory, optional) = params.into_iter().fold( + (vec![], vec![]), + |(mut mandatory, mut optional), parameter| { + if parameter.get_type_info().is_optional { + optional.push(parameter); + } else { + mandatory.push(parameter); + } + + (mandatory, optional) + }, + ); + + Self { + mandatory, + optional, + } + } +} + pub fn parse_api_method(child: &md_parser::TokenTree) -> Option { util::find_content_starts_with(&child.content, "Name: ") .map(|name| { @@ -34,7 +62,7 @@ pub fn parse_api_method(child: &md_parser::TokenTree) -> Option { fn to_api_method(child: &md_parser::TokenTree, name: &str) -> ApiMethod { let method_description = parse_method_description(&child.content); let return_type = parse_return_type(&child.content); - let parameters = parse_parameters(&child.content); + let parameters = parse_parameters(&child.content).map(|params| ApiParameters::new(params)); let method_url = get_method_url(&child.content); ApiMethod { diff --git a/qbittorrent-web-api-gen/src/parser/group/mod.rs b/qbittorrent-web-api-gen/src/parser/group/mod.rs index b7b4036..fb65ccf 100644 --- a/qbittorrent-web-api-gen/src/parser/group/mod.rs +++ b/qbittorrent-web-api-gen/src/parser/group/mod.rs @@ -5,7 +5,7 @@ mod url; use crate::md_parser; use self::{description::parse_group_description, method::parse_api_method, url::get_group_url}; -pub use method::{ApiMethod, ReturnType}; +pub use method::*; #[derive(Debug)] pub struct ApiGroup { diff --git a/qbittorrent-web-api-gen/src/parser/mod.rs b/qbittorrent-web-api-gen/src/parser/mod.rs index 8974168..414d179 100644 --- a/qbittorrent-web-api-gen/src/parser/mod.rs +++ b/qbittorrent-web-api-gen/src/parser/mod.rs @@ -12,7 +12,7 @@ pub struct ReturnTypeParameter { pub return_type: types::Type, } -pub use group::{ApiGroup, ApiMethod, ReturnType}; +pub use group::*; pub fn parse_api_groups(token_tree: md_parser::TokenTree) -> Vec { parse_groups(extract_relevant_parts(token_tree)) From 9451c15cdfc4eb7ae1612f5876192661733cadc9 Mon Sep 17 00:00:00 2001 From: Joel Wachsler Date: Thu, 14 Jul 2022 21:17:27 +0000 Subject: [PATCH 13/47] Refactor parameters --- .../group/method/method_with_params.rs | 165 ++++++++++++------ .../src/parser/group/method/mod.rs | 2 +- 2 files changed, 108 insertions(+), 59 deletions(-) diff --git a/qbittorrent-web-api-gen/src/generate/group/method/method_with_params.rs b/qbittorrent-web-api-gen/src/generate/group/method/method_with_params.rs index a25e844..edc3964 100644 --- a/qbittorrent-web-api-gen/src/generate/group/method/method_with_params.rs +++ b/qbittorrent-web-api-gen/src/generate/group/method/method_with_params.rs @@ -1,7 +1,13 @@ +use std::rc::Rc; + use case::CaseExt; use quote::quote; -use crate::{generate::util, parser, types}; +use crate::{ + generate::util, + parser::{self, ApiParameters}, + types, +}; use super::{return_type::create_return_type, send_method_builder::SendMethodBuilder}; @@ -18,12 +24,13 @@ pub fn create_method_with_params( method.name.to_camel() )); - let mandatory_param_args = generate_mandatory_params(¶ms.mandatory); + let rc_params = Rc::new(params); - let mandatory_param_names = params.mandatory.iter().map(|param| { - let (name, ..) = param_name(param); - quote! { #name } - }); + let mandatory_params = MandatoryParams::new(&rc_params); + let optional_params = OptionalParams::new(&rc_params); + + // let mandatory_param_args = generate_mandatory_params(¶ms.mandatory); + let mandatory_param_args = mandatory_params.generate_mandatory_params(); let group_name = util::to_ident(&group.name.to_camel()); let send_builder = @@ -31,8 +38,8 @@ pub fn create_method_with_params( .with_form(); let generate_send_impl = |send_method: proc_macro2::TokenStream| { - let optional_params = generate_optional_params(¶ms.optional); - let mandatory_param_form_build = generate_mandatory_param_builder(¶ms.mandatory); + let optional_params = optional_params.generate_optional_params(); + let mandatory_param_form_build = mandatory_params.param_builder(); quote! { impl<'a> #param_type<'a> { @@ -60,6 +67,8 @@ pub fn create_method_with_params( None => generate_send_impl(send_builder.build()), }; + let mandatory_param_names = mandatory_params.names(); + let builder = util::add_docs( &method.description, quote! { @@ -81,61 +90,101 @@ pub fn create_method_with_params( (builder, Some(group_impl)) } -fn generate_mandatory_params(mandatory_params: &[types::Type]) -> Vec { - mandatory_params.iter().map(param_with_name).collect() +#[derive(Debug)] +struct MandatoryParams<'a> { + params: &'a ApiParameters, } -fn generate_mandatory_param_builder( - mandatory_params: &[types::Type], -) -> Vec { - mandatory_params - .iter() - .map(|param| { - let (name, name_as_str) = param_name(param); - quote! { let form = form.text(#name_as_str, #name.to_string()); } - }) - .collect() +impl<'a> MandatoryParams<'a> { + fn new(params: &'a ApiParameters) -> Self { + Self { params } + } + + fn generate_mandatory_params(&self) -> Vec { + self.params + .mandatory + .iter() + .map(Self::param_with_name) + .collect() + } + + fn param_with_name(param: &types::Type) -> proc_macro2::TokenStream { + let t = util::to_ident(¶m.to_borrowed_type()); + + let (name, ..) = Self::name(param); + let t = if param.should_borrow() { + quote! { &#t } + } else { + quote! { #t } + }; + + quote! { #name: #t } + } + + fn param_builder(&self) -> Vec { + self.params + .mandatory + .iter() + .map(|param| { + let (name, name_as_str) = Self::name(param); + quote! { let form = form.text(#name_as_str, #name.to_string()); } + }) + .collect() + } + + fn names(&self) -> Vec { + self.params + .mandatory + .iter() + .map(|param| { + let (name, ..) = Self::name(param); + quote! { #name } + }) + .collect() + } + + fn name(param: &types::Type) -> (proc_macro2::Ident, String) { + let name_as_str = param.get_type_info().name.to_snake(); + (util::to_ident(&name_as_str), name_as_str) + } } -fn generate_optional_params(params: &[types::Type]) -> Vec { - params.iter().map(generate_optional_param).collect() +#[derive(Debug)] +struct OptionalParams<'a> { + params: &'a ApiParameters, } -fn generate_optional_param(param: &types::Type) -> proc_macro2::TokenStream { - let n = ¶m.get_type_info().name; - let name = util::to_ident(&n.to_snake()); - let t = util::to_ident(¶m.to_borrowed_type()); - let builder_param = if param.should_borrow() { - quote! { &#t } - } else { - quote! { #t } - }; +impl<'a> OptionalParams<'a> { + fn new(params: &'a ApiParameters) -> Self { + Self { params } + } - util::add_docs( - ¶m.get_type_info().description, - quote! { - pub fn #name(mut self, value: #builder_param) -> Self { - self.form = self.form.text(#n, value.to_string()); - self - } - }, - ) -} - -fn param_name(param: &types::Type) -> (proc_macro2::Ident, String) { - let name_as_str = param.get_type_info().name.to_snake(); - (util::to_ident(&name_as_str), name_as_str) -} - -fn param_with_name(param: &types::Type) -> proc_macro2::TokenStream { - let t = util::to_ident(¶m.to_borrowed_type()); - - let (name, ..) = param_name(param); - let t = if param.should_borrow() { - quote! { &#t } - } else { - quote! { #t } - }; - - quote! { #name: #t } + fn generate_optional_params(&self) -> Vec { + self.params + .optional + .iter() + .map(Self::generate_optional_param) + .collect() + } + + fn generate_optional_param(param: &types::Type) -> proc_macro2::TokenStream { + let n = ¶m.get_type_info().name; + let name = util::to_ident(&n.to_snake()); + let t = util::to_ident(¶m.to_borrowed_type()); + let builder_param = if param.should_borrow() { + quote! { &#t } + } else { + quote! { #t } + }; + + util::add_docs( + ¶m.get_type_info().description, + quote! { + pub fn #name(mut self, value: #builder_param) -> Self { + self.form = self.form.text(#n, value.to_string()); + self + } + }, + ) + } } diff --git a/qbittorrent-web-api-gen/src/parser/group/method/mod.rs b/qbittorrent-web-api-gen/src/parser/group/method/mod.rs index 64a154d..a2a72b1 100644 --- a/qbittorrent-web-api-gen/src/parser/group/method/mod.rs +++ b/qbittorrent-web-api-gen/src/parser/group/method/mod.rs @@ -62,7 +62,7 @@ pub fn parse_api_method(child: &md_parser::TokenTree) -> Option { fn to_api_method(child: &md_parser::TokenTree, name: &str) -> ApiMethod { let method_description = parse_method_description(&child.content); let return_type = parse_return_type(&child.content); - let parameters = parse_parameters(&child.content).map(|params| ApiParameters::new(params)); + let parameters = parse_parameters(&child.content).map(ApiParameters::new); let method_url = get_method_url(&child.content); ApiMethod { From c4ceb686c4d1e135ba9f76ce4694471d6472e5ff Mon Sep 17 00:00:00 2001 From: Joel Wachsler Date: Thu, 14 Jul 2022 21:33:25 +0000 Subject: [PATCH 14/47] Move methods to new parameter struct --- .../group/method/method_with_params.rs | 83 ++++++++++++------- 1 file changed, 51 insertions(+), 32 deletions(-) diff --git a/qbittorrent-web-api-gen/src/generate/group/method/method_with_params.rs b/qbittorrent-web-api-gen/src/generate/group/method/method_with_params.rs index edc3964..72b4188 100644 --- a/qbittorrent-web-api-gen/src/generate/group/method/method_with_params.rs +++ b/qbittorrent-web-api-gen/src/generate/group/method/method_with_params.rs @@ -29,8 +29,7 @@ pub fn create_method_with_params( let mandatory_params = MandatoryParams::new(&rc_params); let optional_params = OptionalParams::new(&rc_params); - // let mandatory_param_args = generate_mandatory_params(¶ms.mandatory); - let mandatory_param_args = mandatory_params.generate_mandatory_params(); + let mandatory_param_args = mandatory_params.generate_params(); let group_name = util::to_ident(&group.name.to_camel()); let send_builder = @@ -38,7 +37,7 @@ pub fn create_method_with_params( .with_form(); let generate_send_impl = |send_method: proc_macro2::TokenStream| { - let optional_params = optional_params.generate_optional_params(); + let optional_params = optional_params.generate_params(); let mandatory_param_form_build = mandatory_params.param_builder(); quote! { @@ -100,34 +99,23 @@ impl<'a> MandatoryParams<'a> { Self { params } } - fn generate_mandatory_params(&self) -> Vec { + fn generate_params(&self) -> Vec { self.params .mandatory .iter() - .map(Self::param_with_name) + .map(|p| p.to_parameter().generate_param_with_name()) .collect() } - fn param_with_name(param: &types::Type) -> proc_macro2::TokenStream { - let t = util::to_ident(¶m.to_borrowed_type()); - - let (name, ..) = Self::name(param); - let t = if param.should_borrow() { - quote! { &#t } - } else { - quote! { #t } - }; - - quote! { #name: #t } - } - fn param_builder(&self) -> Vec { self.params .mandatory .iter() + .map(|p| p.to_parameter()) .map(|param| { - let (name, name_as_str) = Self::name(param); - quote! { let form = form.text(#name_as_str, #name.to_string()); } + let name_ident = param.name_ident(); + let name = param.name(); + quote! { let form = form.text(#name, #name_ident.to_string()); } }) .collect() } @@ -136,17 +124,10 @@ impl<'a> MandatoryParams<'a> { self.params .mandatory .iter() - .map(|param| { - let (name, ..) = Self::name(param); - quote! { #name } - }) + .map(|p| p.to_parameter().name_ident()) + .map(|name_ident| quote! { #name_ident }) .collect() } - - fn name(param: &types::Type) -> (proc_macro2::Ident, String) { - let name_as_str = param.get_type_info().name.to_snake(); - (util::to_ident(&name_as_str), name_as_str) - } } #[derive(Debug)] @@ -159,15 +140,15 @@ impl<'a> OptionalParams<'a> { Self { params } } - fn generate_optional_params(&self) -> Vec { + fn generate_params(&self) -> Vec { self.params .optional .iter() - .map(Self::generate_optional_param) + .map(Self::generate_param) .collect() } - fn generate_optional_param(param: &types::Type) -> proc_macro2::TokenStream { + fn generate_param(param: &types::Type) -> proc_macro2::TokenStream { let n = ¶m.get_type_info().name; let name = util::to_ident(&n.to_snake()); let t = util::to_ident(¶m.to_borrowed_type()); @@ -188,3 +169,41 @@ impl<'a> OptionalParams<'a> { ) } } + +#[derive(Debug)] +struct Parameter<'a> { + p_type: &'a types::Type, +} + +impl<'a> Parameter<'a> { + fn new(p_type: &'a types::Type) -> Self { + Self { p_type } + } + + fn name(&self) -> String { + self.p_type.get_type_info().name.to_snake() + } + + fn name_ident(&self) -> proc_macro2::Ident { + util::to_ident(&self.name()) + } + + fn generate_param_with_name(&self) -> proc_macro2::TokenStream { + let t = util::to_ident(&self.p_type.to_borrowed_type()); + + let name_ident = self.name_ident(); + let t = if self.p_type.should_borrow() { + quote! { &#t } + } else { + quote! { #t } + }; + + quote! { #name_ident: #t } + } +} + +impl types::Type { + fn to_parameter<'a>(&'a self) -> Parameter<'a> { + Parameter::new(self) + } +} From a24e4c5d8d0d69b991f5bea1e420888d84e874e5 Mon Sep 17 00:00:00 2001 From: Joel Wachsler Date: Thu, 14 Jul 2022 21:34:09 +0000 Subject: [PATCH 15/47] Fix warning --- .../src/generate/group/method/method_with_params.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qbittorrent-web-api-gen/src/generate/group/method/method_with_params.rs b/qbittorrent-web-api-gen/src/generate/group/method/method_with_params.rs index 72b4188..a404a9d 100644 --- a/qbittorrent-web-api-gen/src/generate/group/method/method_with_params.rs +++ b/qbittorrent-web-api-gen/src/generate/group/method/method_with_params.rs @@ -203,7 +203,7 @@ impl<'a> Parameter<'a> { } impl types::Type { - fn to_parameter<'a>(&'a self) -> Parameter<'a> { + fn to_parameter(&self) -> Parameter<'_> { Parameter::new(self) } } From 464c9b099dce948b000c8ee7b6ee543de5316596 Mon Sep 17 00:00:00 2001 From: Joel Wachsler Date: Thu, 14 Jul 2022 22:45:57 +0000 Subject: [PATCH 16/47] Extract send impl --- .../group/method/method_with_params.rs | 131 ++++++++++++------ 1 file changed, 91 insertions(+), 40 deletions(-) diff --git a/qbittorrent-web-api-gen/src/generate/group/method/method_with_params.rs b/qbittorrent-web-api-gen/src/generate/group/method/method_with_params.rs index a404a9d..d9003dd 100644 --- a/qbittorrent-web-api-gen/src/generate/group/method/method_with_params.rs +++ b/qbittorrent-web-api-gen/src/generate/group/method/method_with_params.rs @@ -1,6 +1,7 @@ use std::rc::Rc; use case::CaseExt; +use proc_macro2::TokenStream; use quote::quote; use crate::{ @@ -17,56 +18,38 @@ pub fn create_method_with_params( params: &parser::ApiParameters, method_name: &proc_macro2::Ident, url: &str, -) -> (proc_macro2::TokenStream, Option) { +) -> (TokenStream, Option) { let param_type = util::to_ident(&format!( "{}{}Parameters", group.name.to_camel(), method.name.to_camel() )); - let rc_params = Rc::new(params); + let parameters = Parameters::new(params); - let mandatory_params = MandatoryParams::new(&rc_params); - let optional_params = OptionalParams::new(&rc_params); - - let mandatory_param_args = mandatory_params.generate_params(); + let mandatory_param_args = parameters.mandatory.generate_params(); let group_name = util::to_ident(&group.name.to_camel()); let send_builder = SendMethodBuilder::new(&util::to_ident("send"), url, quote! { self.group.auth }) .with_form(); - let generate_send_impl = |send_method: proc_macro2::TokenStream| { - let optional_params = optional_params.generate_params(); - let mandatory_param_form_build = mandatory_params.param_builder(); - - quote! { - impl<'a> #param_type<'a> { - fn new(group: &'a #group_name, #(#mandatory_param_args),*) -> Self { - let form = reqwest::multipart::Form::new(); - #(#mandatory_param_form_build)* - Self { group, form } - } - - #(#optional_params)* - #send_method - } - } - }; + let send_impl_generator = SendImplGenerator::new(&group_name, ¶meters, ¶m_type); let send = match create_return_type(group, method) { Some((return_type_name, return_type)) => { - let send_impl = generate_send_impl(send_builder.return_type(&return_type_name).build()); + let send_impl = + send_impl_generator.generate(send_builder.return_type(&return_type_name)); quote! { #send_impl #return_type } } - None => generate_send_impl(send_builder.build()), + None => send_impl_generator.generate(send_builder), }; - let mandatory_param_names = mandatory_params.names(); + let mandatory_param_names = parameters.mandatory.names(); let builder = util::add_docs( &method.description, @@ -89,6 +72,71 @@ pub fn create_method_with_params( (builder, Some(group_impl)) } +#[derive(Debug)] +struct SendImplGenerator<'a> { + group_name: &'a proc_macro2::Ident, + parameters: &'a Parameters<'a>, + param_type: &'a proc_macro2::Ident, +} + +impl<'a> SendImplGenerator<'a> { + fn new( + group_name: &'a proc_macro2::Ident, + parameters: &'a Parameters<'a>, + param_type: &'a proc_macro2::Ident, + ) -> Self { + Self { + group_name, + parameters, + param_type, + } + } + + fn generate(&self, send_method_builder: SendMethodBuilder) -> TokenStream { + let parameters = self.parameters; + + let optional_builder_methods = parameters.optional.generate_builder_methods(); + let mandatory_param_form_build = parameters.mandatory.form_builder(); + let mandatory_param_args = parameters.mandatory.generate_params(); + let param_type = self.param_type; + let group_name = self.group_name; + let send_method = send_method_builder.build(); + + quote! { + impl<'a> #param_type<'a> { + fn new(group: &'a #group_name, #(#mandatory_param_args),*) -> Self { + let form = reqwest::multipart::Form::new(); + #(#mandatory_param_form_build)* + Self { group, form } + } + + #(#optional_builder_methods)* + #send_method + } + } + } +} + +#[derive(Debug)] +struct Parameters<'a> { + mandatory: MandatoryParams<'a>, + optional: OptionalParams<'a>, +} + +impl<'a> Parameters<'a> { + fn new(api_parameters: &'a ApiParameters) -> Self { + let rc_params = Rc::new(api_parameters); + + let mandatory = MandatoryParams::new(&rc_params); + let optional = OptionalParams::new(&rc_params); + + Self { + mandatory, + optional, + } + } +} + #[derive(Debug)] struct MandatoryParams<'a> { params: &'a ApiParameters, @@ -99,7 +147,7 @@ impl<'a> MandatoryParams<'a> { Self { params } } - fn generate_params(&self) -> Vec { + fn generate_params(&self) -> Vec { self.params .mandatory .iter() @@ -107,7 +155,7 @@ impl<'a> MandatoryParams<'a> { .collect() } - fn param_builder(&self) -> Vec { + fn form_builder(&self) -> Vec { self.params .mandatory .iter() @@ -120,7 +168,7 @@ impl<'a> MandatoryParams<'a> { .collect() } - fn names(&self) -> Vec { + fn names(&self) -> Vec { self.params .mandatory .iter() @@ -140,29 +188,32 @@ impl<'a> OptionalParams<'a> { Self { params } } - fn generate_params(&self) -> Vec { + fn generate_builder_methods(&self) -> Vec { self.params .optional .iter() - .map(Self::generate_param) + .map(Self::generate_builder_method) .collect() } - fn generate_param(param: &types::Type) -> proc_macro2::TokenStream { - let n = ¶m.get_type_info().name; - let name = util::to_ident(&n.to_snake()); - let t = util::to_ident(¶m.to_borrowed_type()); + fn generate_builder_method(param: &types::Type) -> TokenStream { + let parameter = param.to_parameter(); + let name = parameter.name(); + let name_ident = parameter.name_ident(); + + let param_type = util::to_ident(¶m.to_borrowed_type()); + let builder_param = if param.should_borrow() { - quote! { &#t } + quote! { &#param_type } } else { - quote! { #t } + quote! { #param_type } }; util::add_docs( ¶m.get_type_info().description, quote! { - pub fn #name(mut self, value: #builder_param) -> Self { - self.form = self.form.text(#n, value.to_string()); + pub fn #name_ident(mut self, value: #builder_param) -> Self { + self.form = self.form.text(#name, value.to_string()); self } }, @@ -188,7 +239,7 @@ impl<'a> Parameter<'a> { util::to_ident(&self.name()) } - fn generate_param_with_name(&self) -> proc_macro2::TokenStream { + fn generate_param_with_name(&self) -> TokenStream { let t = util::to_ident(&self.p_type.to_borrowed_type()); let name_ident = self.name_ident(); From 72074f60c1cc650a8cd8c4df11a0ebd6d7078e02 Mon Sep 17 00:00:00 2001 From: Joel Wachsler Date: Thu, 14 Jul 2022 22:53:41 +0000 Subject: [PATCH 17/47] Extract builder generation --- .../group/method/method_with_params.rs | 34 ++++++++++++------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/qbittorrent-web-api-gen/src/generate/group/method/method_with_params.rs b/qbittorrent-web-api-gen/src/generate/group/method/method_with_params.rs index d9003dd..a41e3c1 100644 --- a/qbittorrent-web-api-gen/src/generate/group/method/method_with_params.rs +++ b/qbittorrent-web-api-gen/src/generate/group/method/method_with_params.rs @@ -6,7 +6,7 @@ use quote::quote; use crate::{ generate::util, - parser::{self, ApiParameters}, + parser::{self, ApiMethod, ApiParameters}, types, }; @@ -27,8 +27,6 @@ pub fn create_method_with_params( let parameters = Parameters::new(params); - let mandatory_param_args = parameters.mandatory.generate_params(); - let group_name = util::to_ident(&group.name.to_camel()); let send_builder = SendMethodBuilder::new(&util::to_ident("send"), url, quote! { self.group.auth }) @@ -49,16 +47,7 @@ pub fn create_method_with_params( None => send_impl_generator.generate(send_builder), }; - let mandatory_param_names = parameters.mandatory.names(); - - let builder = util::add_docs( - &method.description, - quote! { - pub fn #method_name(&self, #(#mandatory_param_args),*) -> #param_type { - #param_type::new(self, #(#mandatory_param_names),*) - } - }, - ); + let builder = generate_builder(¶meters, method, method_name, ¶m_type); let group_impl = quote! { pub struct #param_type<'a> { @@ -72,6 +61,25 @@ pub fn create_method_with_params( (builder, Some(group_impl)) } +fn generate_builder( + parameters: &Parameters, + method: &ApiMethod, + method_name: &proc_macro2::Ident, + param_type: &proc_macro2::Ident, +) -> proc_macro2::TokenStream { + let mandatory_param_names = parameters.mandatory.names(); + let mandatory_param_args = parameters.mandatory.generate_params(); + + util::add_docs( + &method.description, + quote! { + pub fn #method_name(&self, #(#mandatory_param_args),*) -> #param_type { + #param_type::new(self, #(#mandatory_param_names),*) + } + }, + ) +} + #[derive(Debug)] struct SendImplGenerator<'a> { group_name: &'a proc_macro2::Ident, From 4a862d6e36c207aa014585b7641dd5221f05e462 Mon Sep 17 00:00:00 2001 From: Joel Wachsler Date: Thu, 14 Jul 2022 23:04:55 +0000 Subject: [PATCH 18/47] Simplify parameter handling --- .../group/method/method_with_params.rs | 44 +++++++++---------- 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/qbittorrent-web-api-gen/src/generate/group/method/method_with_params.rs b/qbittorrent-web-api-gen/src/generate/group/method/method_with_params.rs index a41e3c1..2c72049 100644 --- a/qbittorrent-web-api-gen/src/generate/group/method/method_with_params.rs +++ b/qbittorrent-web-api-gen/src/generate/group/method/method_with_params.rs @@ -147,27 +147,26 @@ impl<'a> Parameters<'a> { #[derive(Debug)] struct MandatoryParams<'a> { - params: &'a ApiParameters, + params: Vec>, } impl<'a> MandatoryParams<'a> { fn new(params: &'a ApiParameters) -> Self { - Self { params } + Self { + params: Parameter::from(¶ms.mandatory), + } } fn generate_params(&self) -> Vec { self.params - .mandatory .iter() - .map(|p| p.to_parameter().generate_param_with_name()) + .map(|p| p.generate_param_with_name()) .collect() } fn form_builder(&self) -> Vec { self.params - .mandatory .iter() - .map(|p| p.to_parameter()) .map(|param| { let name_ident = param.name_ident(); let name = param.name(); @@ -178,9 +177,8 @@ impl<'a> MandatoryParams<'a> { fn names(&self) -> Vec { self.params - .mandatory .iter() - .map(|p| p.to_parameter().name_ident()) + .map(|p| p.name_ident()) .map(|name_ident| quote! { #name_ident }) .collect() } @@ -188,37 +186,37 @@ impl<'a> MandatoryParams<'a> { #[derive(Debug)] struct OptionalParams<'a> { - params: &'a ApiParameters, + params: Vec>, } impl<'a> OptionalParams<'a> { fn new(params: &'a ApiParameters) -> Self { - Self { params } + Self { + params: Parameter::from(¶ms.optional), + } } fn generate_builder_methods(&self) -> Vec { self.params - .optional .iter() .map(Self::generate_builder_method) .collect() } - fn generate_builder_method(param: &types::Type) -> TokenStream { - let parameter = param.to_parameter(); - let name = parameter.name(); - let name_ident = parameter.name_ident(); + fn generate_builder_method(param: &Parameter) -> TokenStream { + let name = param.name(); + let name_ident = param.name_ident(); - let param_type = util::to_ident(¶m.to_borrowed_type()); + let param_type = util::to_ident(¶m.p_type.to_borrowed_type()); - let builder_param = if param.should_borrow() { + let builder_param = if param.p_type.should_borrow() { quote! { &#param_type } } else { quote! { #param_type } }; util::add_docs( - ¶m.get_type_info().description, + ¶m.p_type.get_type_info().description, quote! { pub fn #name_ident(mut self, value: #builder_param) -> Self { self.form = self.form.text(#name, value.to_string()); @@ -239,6 +237,10 @@ impl<'a> Parameter<'a> { Self { p_type } } + fn from(parameters: &[types::Type]) -> Vec> { + parameters.iter().map(Parameter::new).collect() + } + fn name(&self) -> String { self.p_type.get_type_info().name.to_snake() } @@ -260,9 +262,3 @@ impl<'a> Parameter<'a> { quote! { #name_ident: #t } } } - -impl types::Type { - fn to_parameter(&self) -> Parameter<'_> { - Parameter::new(self) - } -} From 9830aa40a6f05807df5a6948dd4a5277dfad607a Mon Sep 17 00:00:00 2001 From: Joel Wachsler Date: Thu, 14 Jul 2022 23:16:59 +0000 Subject: [PATCH 19/47] Use struct for return type --- .../group/method/method_with_params.rs | 63 +++++++++++-------- .../group/method/method_without_params.rs | 21 ++++--- .../src/generate/group/method/mod.rs | 36 ++++++++--- 3 files changed, 76 insertions(+), 44 deletions(-) diff --git a/qbittorrent-web-api-gen/src/generate/group/method/method_with_params.rs b/qbittorrent-web-api-gen/src/generate/group/method/method_with_params.rs index 2c72049..1431011 100644 --- a/qbittorrent-web-api-gen/src/generate/group/method/method_with_params.rs +++ b/qbittorrent-web-api-gen/src/generate/group/method/method_with_params.rs @@ -10,7 +10,9 @@ use crate::{ types, }; -use super::{return_type::create_return_type, send_method_builder::SendMethodBuilder}; +use super::{ + return_type::create_return_type, send_method_builder::SendMethodBuilder, MethodsAndExtra, +}; pub fn create_method_with_params( group: &parser::ApiGroup, @@ -18,7 +20,7 @@ pub fn create_method_with_params( params: &parser::ApiParameters, method_name: &proc_macro2::Ident, url: &str, -) -> (TokenStream, Option) { +) -> MethodsAndExtra { let param_type = util::to_ident(&format!( "{}{}Parameters", group.name.to_camel(), @@ -27,38 +29,43 @@ pub fn create_method_with_params( let parameters = Parameters::new(params); - let group_name = util::to_ident(&group.name.to_camel()); - let send_builder = - SendMethodBuilder::new(&util::to_ident("send"), url, quote! { self.group.auth }) - .with_form(); + if parameters.optional.is_empty() { + let fooz = quote! {}; + MethodsAndExtra::new(fooz) + } else { + let group_name = util::to_ident(&group.name.to_camel()); + let send_builder = + SendMethodBuilder::new(&util::to_ident("send"), url, quote! { self.group.auth }) + .with_form(); - let send_impl_generator = SendImplGenerator::new(&group_name, ¶meters, ¶m_type); + let send_impl_generator = SendImplGenerator::new(&group_name, ¶meters, ¶m_type); - let send = match create_return_type(group, method) { - Some((return_type_name, return_type)) => { - let send_impl = - send_impl_generator.generate(send_builder.return_type(&return_type_name)); + let send = match create_return_type(group, method) { + Some((return_type_name, return_type)) => { + let send_impl = + send_impl_generator.generate(send_builder.return_type(&return_type_name)); - quote! { - #send_impl - #return_type + quote! { + #send_impl + #return_type + } } - } - None => send_impl_generator.generate(send_builder), - }; + None => send_impl_generator.generate(send_builder), + }; - let builder = generate_builder(¶meters, method, method_name, ¶m_type); + let builder = generate_builder(¶meters, method, method_name, ¶m_type); - let group_impl = quote! { - pub struct #param_type<'a> { - group: &'a #group_name<'a>, - form: reqwest::multipart::Form, - } + let group_impl = quote! { + pub struct #param_type<'a> { + group: &'a #group_name<'a>, + form: reqwest::multipart::Form, + } - #send - }; + #send + }; - (builder, Some(group_impl)) + MethodsAndExtra::new(builder).with_structs(group_impl) + } } fn generate_builder( @@ -196,6 +203,10 @@ impl<'a> OptionalParams<'a> { } } + fn is_empty(&self) -> bool { + self.params.is_empty() + } + fn generate_builder_methods(&self) -> Vec { self.params .iter() diff --git a/qbittorrent-web-api-gen/src/generate/group/method/method_without_params.rs b/qbittorrent-web-api-gen/src/generate/group/method/method_without_params.rs index b705257..ec1d3a7 100644 --- a/qbittorrent-web-api-gen/src/generate/group/method/method_without_params.rs +++ b/qbittorrent-web-api-gen/src/generate/group/method/method_without_params.rs @@ -1,6 +1,8 @@ use quote::quote; -use super::{return_type::create_return_type, send_method_builder::SendMethodBuilder}; +use super::{ + return_type::create_return_type, send_method_builder::SendMethodBuilder, MethodsAndExtra, +}; use crate::parser; pub fn create_method_without_params( @@ -8,19 +10,18 @@ pub fn create_method_without_params( method: &parser::ApiMethod, method_name: proc_macro2::Ident, url: &str, -) -> (proc_macro2::TokenStream, Option) { +) -> MethodsAndExtra { let builder = SendMethodBuilder::new(&method_name, url, quote! { self.auth }) .description(&method.description); match create_return_type(group, method) { - Some((return_type_name, return_type)) => ( - builder.return_type(&return_type_name).build(), - Some(return_type), - ), - None => ( - builder.build(), + Some((return_type_name, return_type)) => { + MethodsAndExtra::new(builder.return_type(&return_type_name).build()) + .with_structs(return_type) + } + None => { // assume that all methods without a return type returns a string - None, - ), + MethodsAndExtra::new(builder.build()) + } } } diff --git a/qbittorrent-web-api-gen/src/generate/group/method/mod.rs b/qbittorrent-web-api-gen/src/generate/group/method/mod.rs index 3c2ea73..041cec4 100644 --- a/qbittorrent-web-api-gen/src/generate/group/method/mod.rs +++ b/qbittorrent-web-api-gen/src/generate/group/method/mod.rs @@ -17,13 +17,16 @@ pub fn generate_methods( auth: &syn::Ident, group_name_camel: &syn::Ident, ) -> proc_macro2::TokenStream { - let methods_and_param_structs = group + let methods_and_extra = group .methods .iter() .map(|method| generate_method(group, method)); - let methods = methods_and_param_structs.clone().map(|(method, ..)| method); - let structs = methods_and_param_structs.flat_map(|(_, s)| s); + let methods = methods_and_extra + .clone() + .map(|MethodsAndExtra { methods, .. }| methods); + + let extra = methods_and_extra.flat_map(|MethodsAndExtra { extra: structs, .. }| structs); quote! { impl <'a> #group_name_camel<'a> { @@ -34,14 +37,31 @@ pub fn generate_methods( #(#methods)* } - #(#structs)* + #(#extra)* } } -fn generate_method( - group: &parser::ApiGroup, - method: &parser::ApiMethod, -) -> (proc_macro2::TokenStream, Option) { +#[derive(Debug)] +pub struct MethodsAndExtra { + methods: proc_macro2::TokenStream, + extra: Option, +} + +impl MethodsAndExtra { + pub fn new(methods: proc_macro2::TokenStream) -> Self { + Self { + methods, + extra: None, + } + } + + pub fn with_structs(mut self, structs: proc_macro2::TokenStream) -> Self { + self.extra = Some(structs); + self + } +} + +fn generate_method(group: &parser::ApiGroup, method: &parser::ApiMethod) -> MethodsAndExtra { let method_name = util::to_ident(&method.name.to_snake()); let url = format!("/api/v2/{}/{}", group.url, method.url); From cc9aeaf6dba76160eb289e92a2277e0789b2564b Mon Sep 17 00:00:00 2001 From: Joel Wachsler Date: Fri, 15 Jul 2022 00:03:52 +0000 Subject: [PATCH 20/47] Add parameters --- .../group/method/method_with_params.rs | 71 ++++++++++++++++--- .../group/method/send_method_builder.rs | 18 ++++- 2 files changed, 77 insertions(+), 12 deletions(-) diff --git a/qbittorrent-web-api-gen/src/generate/group/method/method_with_params.rs b/qbittorrent-web-api-gen/src/generate/group/method/method_with_params.rs index 1431011..d6d9dc6 100644 --- a/qbittorrent-web-api-gen/src/generate/group/method/method_with_params.rs +++ b/qbittorrent-web-api-gen/src/generate/group/method/method_with_params.rs @@ -28,19 +28,55 @@ pub fn create_method_with_params( )); let parameters = Parameters::new(params); + let has_optional_parameters = !parameters.optional.is_empty(); + let generator = MethodGenerator { + group, + url, + parameters, + param_type, + method, + method_name, + }; - if parameters.optional.is_empty() { - let fooz = quote! {}; - MethodsAndExtra::new(fooz) + if has_optional_parameters { + generator.generate_method_with_builder() } else { - let group_name = util::to_ident(&group.name.to_camel()); - let send_builder = - SendMethodBuilder::new(&util::to_ident("send"), url, quote! { self.group.auth }) - .with_form(); + generator.generate_method_without_builder() + } +} - let send_impl_generator = SendImplGenerator::new(&group_name, ¶meters, ¶m_type); +#[derive(Debug)] +struct MethodGenerator<'a> { + group: &'a parser::ApiGroup, + url: &'a str, + parameters: Parameters<'a>, + param_type: proc_macro2::Ident, + method: &'a ApiMethod, + method_name: &'a proc_macro2::Ident, +} - let send = match create_return_type(group, method) { +impl<'a> MethodGenerator<'a> { + fn generate_method_without_builder(&self) -> MethodsAndExtra { + let builder = SendMethodBuilder::new(self.method_name, self.url, quote! { self.auth }) + .description(&self.method.description) + .with_args(&self.parameters.mandatory.generate_params()); + + match create_return_type(self.group, self.method) { + Some((return_type_name, return_type)) => { + MethodsAndExtra::new(builder.return_type(&return_type_name).build()) + .with_structs(return_type) + } + None => MethodsAndExtra::new(builder.build()), + } + } + + fn generate_method_with_builder(&self) -> MethodsAndExtra { + let group_name = self.group_name(); + let send_builder = self.send_builder(&util::to_ident("send")); + let send_impl_generator = + SendImplGenerator::new(&group_name, &self.parameters, &self.param_type); + + let send = match create_return_type(self.group, self.method) { Some((return_type_name, return_type)) => { let send_impl = send_impl_generator.generate(send_builder.return_type(&return_type_name)); @@ -52,8 +88,13 @@ pub fn create_method_with_params( } None => send_impl_generator.generate(send_builder), }; - - let builder = generate_builder(¶meters, method, method_name, ¶m_type); + let builder = generate_builder( + &self.parameters, + self.method, + self.method_name, + &self.param_type, + ); + let param_type = &self.param_type; let group_impl = quote! { pub struct #param_type<'a> { @@ -66,6 +107,14 @@ pub fn create_method_with_params( MethodsAndExtra::new(builder).with_structs(group_impl) } + + fn group_name(&self) -> proc_macro2::Ident { + util::to_ident(&self.group.name.to_camel()) + } + + fn send_builder(&self, name: &proc_macro2::Ident) -> SendMethodBuilder { + SendMethodBuilder::new(name, self.url, quote! { self.group.auth }).with_form() + } } fn generate_builder( diff --git a/qbittorrent-web-api-gen/src/generate/group/method/send_method_builder.rs b/qbittorrent-web-api-gen/src/generate/group/method/send_method_builder.rs index da0c44a..0b1194a 100644 --- a/qbittorrent-web-api-gen/src/generate/group/method/send_method_builder.rs +++ b/qbittorrent-web-api-gen/src/generate/group/method/send_method_builder.rs @@ -8,6 +8,7 @@ pub struct SendMethodBuilder { auth_module_path: proc_macro2::TokenStream, return_type: Option, description: Option, + args: Vec, form: bool, } @@ -24,6 +25,7 @@ impl SendMethodBuilder { return_type: None, description: None, form: false, + args: vec![], } } @@ -42,6 +44,14 @@ impl SendMethodBuilder { self } + pub fn with_args(mut self, value: &[proc_macro2::TokenStream]) -> Self { + for v in value { + self.args.push(v.clone()); + } + + self + } + pub fn build(&self) -> proc_macro2::TokenStream { let method_name = &self.method_name; let (return_type, parse_type) = match &self.return_type { @@ -55,11 +65,17 @@ impl SendMethodBuilder { } else { quote! {} }; + let arg_list = &self.args; + let args = if !arg_list.is_empty() { + quote! { , #(#arg_list),* } + } else { + quote! {} + }; util::add_docs( &self.description, quote! { - pub async fn #method_name(self) -> Result<#return_type> { + pub async fn #method_name(self #args) -> Result<#return_type> { let res = #auth_module_path .authenticated_client(#url) #form From 5705f29f1a5de344a05b428e0197d3cfed910183 Mon Sep 17 00:00:00 2001 From: Joel Wachsler Date: Fri, 15 Jul 2022 00:26:54 +0000 Subject: [PATCH 21/47] Add form args --- .../src/generate/group/method/method_with_params.rs | 12 ++++++++---- .../src/generate/group/method/send_method_builder.rs | 12 +++++++++--- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/qbittorrent-web-api-gen/src/generate/group/method/method_with_params.rs b/qbittorrent-web-api-gen/src/generate/group/method/method_with_params.rs index d6d9dc6..5796699 100644 --- a/qbittorrent-web-api-gen/src/generate/group/method/method_with_params.rs +++ b/qbittorrent-web-api-gen/src/generate/group/method/method_with_params.rs @@ -57,9 +57,14 @@ struct MethodGenerator<'a> { impl<'a> MethodGenerator<'a> { fn generate_method_without_builder(&self) -> MethodsAndExtra { + let form_builder = self.parameters.mandatory.form_builder(); + let form_attributes = + quote! { .multipart(reqwest::multipart::Form::new()#(#form_builder)*) }; + let builder = SendMethodBuilder::new(self.method_name, self.url, quote! { self.auth }) .description(&self.method.description) - .with_args(&self.parameters.mandatory.generate_params()); + .with_args(&self.parameters.mandatory.generate_params()) + .with_extra_form_args(&[form_attributes]); match create_return_type(self.group, self.method) { Some((return_type_name, return_type)) => { @@ -169,8 +174,7 @@ impl<'a> SendImplGenerator<'a> { quote! { impl<'a> #param_type<'a> { fn new(group: &'a #group_name, #(#mandatory_param_args),*) -> Self { - let form = reqwest::multipart::Form::new(); - #(#mandatory_param_form_build)* + let form = reqwest::multipart::Form::new()#(#mandatory_param_form_build)*; Self { group, form } } @@ -226,7 +230,7 @@ impl<'a> MandatoryParams<'a> { .map(|param| { let name_ident = param.name_ident(); let name = param.name(); - quote! { let form = form.text(#name, #name_ident.to_string()); } + quote! { .text(#name, #name_ident.to_string()) } }) .collect() } diff --git a/qbittorrent-web-api-gen/src/generate/group/method/send_method_builder.rs b/qbittorrent-web-api-gen/src/generate/group/method/send_method_builder.rs index 0b1194a..ffd3ad8 100644 --- a/qbittorrent-web-api-gen/src/generate/group/method/send_method_builder.rs +++ b/qbittorrent-web-api-gen/src/generate/group/method/send_method_builder.rs @@ -9,6 +9,7 @@ pub struct SendMethodBuilder { return_type: Option, description: Option, args: Vec, + extra_form_args: Vec, form: bool, } @@ -26,6 +27,7 @@ impl SendMethodBuilder { description: None, form: false, args: vec![], + extra_form_args: vec![], } } @@ -45,10 +47,12 @@ impl SendMethodBuilder { } pub fn with_args(mut self, value: &[proc_macro2::TokenStream]) -> Self { - for v in value { - self.args.push(v.clone()); - } + self.args = value.to_vec(); + self + } + pub fn with_extra_form_args(mut self, value: &[proc_macro2::TokenStream]) -> Self { + self.extra_form_args = value.to_vec(); self } @@ -71,6 +75,7 @@ impl SendMethodBuilder { } else { quote! {} }; + let extra_form_args = &self.extra_form_args; util::add_docs( &self.description, @@ -79,6 +84,7 @@ impl SendMethodBuilder { let res = #auth_module_path .authenticated_client(#url) #form + #(#extra_form_args)* .send() .await? #parse_type From 308a0153abd6819151a14b5b1235849a44540012 Mon Sep 17 00:00:00 2001 From: Joel Wachsler Date: Fri, 15 Jul 2022 00:39:10 +0000 Subject: [PATCH 22/47] Return list if StringArray --- .../src/generate/group/method/return_type.rs | 2 +- qbittorrent-web-api-gen/src/types.rs | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/qbittorrent-web-api-gen/src/generate/group/method/return_type.rs b/qbittorrent-web-api-gen/src/generate/group/method/return_type.rs index 4fc68f5..a4a171a 100644 --- a/qbittorrent-web-api-gen/src/generate/group/method/return_type.rs +++ b/qbittorrent-web-api-gen/src/generate/group/method/return_type.rs @@ -118,7 +118,7 @@ fn generate_builder_field( None => parameter.return_type.to_owned_type(), }; let rtype = util::to_ident(&enum_name); - let rtype_as_quote = if parameter.return_type.get_type_info().is_list { + let rtype_as_quote = if parameter.return_type.is_list() { quote! { std::vec::Vec<#rtype> } } else { quote! { #rtype } diff --git a/qbittorrent-web-api-gen/src/types.rs b/qbittorrent-web-api-gen/src/types.rs index bf4deca..722c5f9 100644 --- a/qbittorrent-web-api-gen/src/types.rs +++ b/qbittorrent-web-api-gen/src/types.rs @@ -15,7 +15,7 @@ pub struct TypeDescription { pub struct TypeInfo { pub name: String, pub is_optional: bool, - pub is_list: bool, + is_list: bool, pub description: Option, pub type_description: Option, } @@ -63,6 +63,10 @@ impl Type { } } + pub fn is_list(&self) -> bool { + self.get_type_info().is_list || matches!(self, Type::StringArray(_)) + } + pub fn to_borrowed_type(&self) -> String { match self { Type::Number(_) => "i32".into(), From 44b61c5534420dbd8b16787f1f13dfde89575a12 Mon Sep 17 00:00:00 2001 From: Joel Wachsler Date: Sun, 17 Jul 2022 11:26:06 +0000 Subject: [PATCH 23/47] Update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5bb548c..2eefd0a 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # qBittorrent web api for Rust -This is an automatic async implementation of the qBittorrent 4.1 web api. The api generation is based on the wiki markdown file which can be found [here](https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-4.1)). +This is an automatic async implementation of the qBittorrent 4.1 web api. The api generation is based on a forked wiki markdown file describing the api which can be found [here](https://github.com/JoelWachsler/qBittorrent/wiki/WebUI-API-(qBittorrent-4.1)) and the original [here](https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-4.1)). ## Example From 5fb87250dd124ed32a149d2949b2a75f9c3da752 Mon Sep 17 00:00:00 2001 From: Joel Wachsler Date: Sun, 17 Jul 2022 11:26:41 +0000 Subject: [PATCH 24/47] Fix typos --- .devcontainer/devcontainer.json | 3 +- .../src/generate/group/method/return_type.rs | 20 +- .../src/md_parser/md_token.rs | 6 +- .../src/md_parser/token_tree_factory.rs | 4 +- .../token_tree_factory_tests/log.check | 4 +- ... should_remove_surrounding_asterisk.check} | 2 +- ... => should_remove_surrounding_asterisk.md} | 0 .../src/parser/group/method/description.rs | 2 +- .../src/parser/group/method/parameters.rs | 2 +- qbittorrent-web-api-gen/token_tree.txt | 288 +++++++++--------- 10 files changed, 166 insertions(+), 165 deletions(-) rename qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/{should_remove_surrounding_asterix.check => should_remove_surrounding_asterisk.check} (90%) rename qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/{should_remove_surrounding_asterix.md => should_remove_surrounding_asterisk.md} (100%) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 1c4a773..bd3c8b4 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -26,7 +26,8 @@ "tamasfe.even-better-toml", "serayuzgur.crates", "redhat.vscode-yaml", - "eamodio.gitlens" + "eamodio.gitlens", + "streetsidesoftware.code-spell-checker" ] } }, diff --git a/qbittorrent-web-api-gen/src/generate/group/method/return_type.rs b/qbittorrent-web-api-gen/src/generate/group/method/return_type.rs index a4a171a..cba375b 100644 --- a/qbittorrent-web-api-gen/src/generate/group/method/return_type.rs +++ b/qbittorrent-web-api-gen/src/generate/group/method/return_type.rs @@ -111,27 +111,27 @@ fn generate_builder_field( parameter: &parser::ReturnTypeParameter, enum_names: &HashMap, ) -> proc_macro2::TokenStream { - let namestr = ¶meter.name; - let name = util::to_ident(&namestr.to_snake().replace("__", "_")); - let enum_name = match enum_names.get(namestr) { + let name_string = ¶meter.name; + let name = util::to_ident(&name_string.to_snake().replace("__", "_")); + let enum_name = match enum_names.get(name_string) { Some(enum_type) => enum_type.to_owned(), None => parameter.return_type.to_owned_type(), }; - let rtype = util::to_ident(&enum_name); - let rtype_as_quote = if parameter.return_type.is_list() { - quote! { std::vec::Vec<#rtype> } + let return_type = util::to_ident(&enum_name); + let return_type_as_quote = if parameter.return_type.is_list() { + quote! { std::vec::Vec<#return_type> } } else { - quote! { #rtype } + quote! { #return_type } }; let generate_field = |field_name| { quote! { - #[serde(rename = #namestr)] - pub #field_name: #rtype_as_quote + #[serde(rename = #name_string)] + pub #field_name: #return_type_as_quote } }; // "type" is a reserved keyword in Rust, so we just add "t_" to it. - if namestr == "type" { + if name_string == "type" { generate_field(format_ident!("t_{}", name)) } else { generate_field(name) diff --git a/qbittorrent-web-api-gen/src/md_parser/md_token.rs b/qbittorrent-web-api-gen/src/md_parser/md_token.rs index 39de178..fd36c51 100644 --- a/qbittorrent-web-api-gen/src/md_parser/md_token.rs +++ b/qbittorrent-web-api-gen/src/md_parser/md_token.rs @@ -1,7 +1,7 @@ #[derive(Debug, Clone, PartialEq, Eq)] pub enum MdContent { Text(String), - Asterix(String), + Asterisk(String), Table(Table), } @@ -39,7 +39,7 @@ impl MdContent { pub fn inner_value_as_string(&self) -> String { match self { MdContent::Text(text) => text.into(), - MdContent::Asterix(text) => text.into(), + MdContent::Asterisk(text) => text.into(), MdContent::Table(table) => table.raw(), } } @@ -68,7 +68,7 @@ impl MdToken { content: line.trim_matches('#').trim().to_string(), }) } else if line.starts_with('*') { - MdToken::Content(MdContent::Asterix( + MdToken::Content(MdContent::Asterisk( line.trim_matches('*').trim().to_string(), )) } else { diff --git a/qbittorrent-web-api-gen/src/md_parser/token_tree_factory.rs b/qbittorrent-web-api-gen/src/md_parser/token_tree_factory.rs index d04ac8b..ad170ff 100644 --- a/qbittorrent-web-api-gen/src/md_parser/token_tree_factory.rs +++ b/qbittorrent-web-api-gen/src/md_parser/token_tree_factory.rs @@ -113,8 +113,8 @@ mod tests { } #[test] - fn should_remove_surrounding_asterix() { - run_test!("should_remove_surrounding_asterix"); + fn should_remove_surrounding_asterisk() { + run_test!("should_remove_surrounding_asterisk"); } #[test] diff --git a/qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/log.check b/qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/log.check index e19fe27..41a4da1 100644 --- a/qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/log.check +++ b/qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/log.check @@ -32,7 +32,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Parameters:", ), Text( @@ -114,7 +114,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( diff --git a/qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/should_remove_surrounding_asterix.check b/qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/should_remove_surrounding_asterisk.check similarity index 90% rename from qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/should_remove_surrounding_asterix.check rename to qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/should_remove_surrounding_asterisk.check index 2c66917..2255cf5 100644 --- a/qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/should_remove_surrounding_asterix.check +++ b/qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/should_remove_surrounding_asterisk.check @@ -7,7 +7,7 @@ TokenTree { "A", ), content: [ - Asterix( + Asterisk( "B", ), ], diff --git a/qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/should_remove_surrounding_asterix.md b/qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/should_remove_surrounding_asterisk.md similarity index 100% rename from qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/should_remove_surrounding_asterix.md rename to qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/should_remove_surrounding_asterisk.md diff --git a/qbittorrent-web-api-gen/src/parser/group/method/description.rs b/qbittorrent-web-api-gen/src/parser/group/method/description.rs index 73f3fce..dfeab4e 100644 --- a/qbittorrent-web-api-gen/src/parser/group/method/description.rs +++ b/qbittorrent-web-api-gen/src/parser/group/method/description.rs @@ -5,7 +5,7 @@ pub fn parse_method_description(content: &[MdContent]) -> Option { .iter() // skip until we get to the "Returns:" text .skip_while(|row| match row { - MdContent::Asterix(text) => !text.starts_with("Returns:"), + MdContent::Asterisk(text) => !text.starts_with("Returns:"), _ => true, }) // there is one space before the table diff --git a/qbittorrent-web-api-gen/src/parser/group/method/parameters.rs b/qbittorrent-web-api-gen/src/parser/group/method/parameters.rs index ebbfb07..189c160 100644 --- a/qbittorrent-web-api-gen/src/parser/group/method/parameters.rs +++ b/qbittorrent-web-api-gen/src/parser/group/method/parameters.rs @@ -6,7 +6,7 @@ pub fn parse_parameters(content: &[md_parser::MdContent]) -> Option { + md_parser::MdContent::Asterisk(content) | md_parser::MdContent::Text(content) => { !content.starts_with("Parameters:") } _ => true, diff --git a/qbittorrent-web-api-gen/token_tree.txt b/qbittorrent-web-api-gen/token_tree.txt index db4b5e6..2828f1c 100644 --- a/qbittorrent-web-api-gen/token_tree.txt +++ b/qbittorrent-web-api-gen/token_tree.txt @@ -380,7 +380,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "", ), Text( @@ -825,7 +825,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Parameters:", ), Text( @@ -865,7 +865,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -967,7 +967,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Parameters:", ), Text( @@ -979,7 +979,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -1044,7 +1044,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Parameters:", ), Text( @@ -1056,7 +1056,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -1109,7 +1109,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Parameters:", ), Text( @@ -1121,7 +1121,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -1174,7 +1174,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Parameters:", ), Text( @@ -1186,7 +1186,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -1297,7 +1297,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Parameters:", ), Text( @@ -1309,7 +1309,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -1356,7 +1356,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Parameters:", ), Text( @@ -1368,7 +1368,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -3560,7 +3560,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Parameters:", ), Text( @@ -3590,7 +3590,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -3620,7 +3620,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Notes**:", ), Text( @@ -3661,7 +3661,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Parameters:", ), Text( @@ -3673,7 +3673,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -3744,7 +3744,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Parameters:", ), Text( @@ -3826,7 +3826,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -4244,7 +4244,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Parameters:", ), Text( @@ -4276,7 +4276,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -4408,7 +4408,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Parameters:", ), Text( @@ -4458,7 +4458,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -4646,7 +4646,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Parameters:", ), Text( @@ -4704,7 +4704,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -4788,7 +4788,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Parameters:", ), Text( @@ -4800,7 +4800,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -5072,7 +5072,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Parameters:", ), Text( @@ -5084,7 +5084,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -5137,7 +5137,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Parameters:", ), Text( @@ -5149,7 +5149,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -5196,7 +5196,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Parameters:", ), Text( @@ -5208,7 +5208,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -5261,7 +5261,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Parameters:", ), Text( @@ -5293,7 +5293,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -5340,7 +5340,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Parameters:", ), Text( @@ -5352,7 +5352,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -5405,7 +5405,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Parameters:", ), Text( @@ -5437,7 +5437,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -5484,7 +5484,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Parameters:", ), Text( @@ -5517,7 +5517,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -5582,7 +5582,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Parameters:", ), Text( @@ -5689,7 +5689,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -6378,7 +6378,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Parameters:", ), Text( @@ -6410,7 +6410,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -6893,7 +6893,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Parameters:", ), Text( @@ -6925,7 +6925,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -7179,7 +7179,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Parameters:", ), Text( @@ -7211,7 +7211,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -7342,7 +7342,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Parameters:", ), Text( @@ -7383,7 +7383,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -7645,7 +7645,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Parameters:", ), Text( @@ -7677,7 +7677,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -7814,7 +7814,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Parameters:", ), Text( @@ -7846,7 +7846,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -7939,7 +7939,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Parameters:", ), Text( @@ -7997,7 +7997,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -8050,7 +8050,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Parameters:", ), Text( @@ -8108,7 +8108,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -8161,7 +8161,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Parameters:", ), Text( @@ -8219,7 +8219,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -8272,7 +8272,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Parameters:", ), Text( @@ -8330,7 +8330,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -8383,7 +8383,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Parameters:", ), Text( @@ -8441,7 +8441,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -8698,7 +8698,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Parameters:", ), Text( @@ -8858,7 +8858,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -8957,7 +8957,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -9011,7 +9011,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Parameters:", ), Text( @@ -9059,7 +9059,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -9134,7 +9134,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Parameters:", ), Text( @@ -9175,7 +9175,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -9236,7 +9236,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Parameters:", ), Text( @@ -9278,7 +9278,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -9338,7 +9338,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Parameters:", ), Text( @@ -9396,7 +9396,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -9456,7 +9456,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Parameters:", ), Text( @@ -9514,7 +9514,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -9574,7 +9574,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Parameters:", ), Text( @@ -9632,7 +9632,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -9692,7 +9692,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Parameters:", ), Text( @@ -9750,7 +9750,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -9804,7 +9804,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Parameters:", ), Text( @@ -9865,7 +9865,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -10115,7 +10115,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -10227,7 +10227,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -10448,7 +10448,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -10557,7 +10557,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -10664,7 +10664,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -10790,7 +10790,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -10898,7 +10898,7 @@ TokenTree { Text( "```", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -10984,7 +10984,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -11078,7 +11078,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -11178,7 +11178,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -11290,7 +11290,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -11405,7 +11405,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -11488,7 +11488,7 @@ TokenTree { Text( "```", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -11574,7 +11574,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -11663,7 +11663,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -11772,7 +11772,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -11825,7 +11825,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Parameters:", ), Text( @@ -11883,7 +11883,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -11936,7 +11936,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Parameters:", ), Text( @@ -11994,7 +11994,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -12096,7 +12096,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -12198,7 +12198,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -12245,7 +12245,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Parameters:", ), Text( @@ -12293,7 +12293,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -12354,7 +12354,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Parameters:", ), Text( @@ -12402,7 +12402,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -12513,7 +12513,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -12607,7 +12607,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -12699,7 +12699,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -12799,7 +12799,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -12987,7 +12987,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -13072,7 +13072,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -13413,7 +13413,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -13492,7 +13492,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -13614,7 +13614,7 @@ TokenTree { Text( "```", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -13756,7 +13756,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -13824,7 +13824,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Parameters:", ), Text( @@ -13873,7 +13873,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -13983,7 +13983,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Parameters:", ), Text( @@ -14015,7 +14015,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -14069,7 +14069,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Parameters:", ), Text( @@ -14101,7 +14101,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -14239,7 +14239,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Parameters:", ), Text( @@ -14287,7 +14287,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -14379,7 +14379,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Result object:", ), Text( @@ -14563,7 +14563,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Parameters:", ), Text( @@ -14595,7 +14595,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -14649,7 +14649,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Parameters:", ), Text( @@ -14661,7 +14661,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -14882,7 +14882,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Parameters:", ), Text( @@ -14915,7 +14915,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -14962,7 +14962,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Parameters:", ), Text( @@ -14995,7 +14995,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -15042,7 +15042,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Parameters:", ), Text( @@ -15083,7 +15083,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( @@ -15130,7 +15130,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Parameters:", ), Text( @@ -15142,7 +15142,7 @@ TokenTree { Text( "", ), - Asterix( + Asterisk( "Returns:", ), Text( From bebceb658168e9bfd74dbdb688ae3dfa36cdade5 Mon Sep 17 00:00:00 2001 From: Joel Wachsler Date: Sun, 17 Jul 2022 11:30:53 +0000 Subject: [PATCH 25/47] Fix more typos --- qbittorrent-web-api-gen/src/md_parser/md_token.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/qbittorrent-web-api-gen/src/md_parser/md_token.rs b/qbittorrent-web-api-gen/src/md_parser/md_token.rs index fd36c51..139c898 100644 --- a/qbittorrent-web-api-gen/src/md_parser/md_token.rs +++ b/qbittorrent-web-api-gen/src/md_parser/md_token.rs @@ -79,7 +79,7 @@ impl MdToken { pub fn from(content: &str) -> Vec { // to prevent infinite loops let mut max_iterations = 10000; - let mut decreate_max_iterations = || { + let mut decrease_max_iterations = || { max_iterations -= 1; if max_iterations <= 0 { panic!("Max iterations reached, missing termination?"); @@ -90,7 +90,7 @@ impl MdToken { let mut iter = content.lines().peekable(); while let Some(line) = iter.next() { - decreate_max_iterations(); + decrease_max_iterations(); // assume this is a table if line.contains('|') { @@ -109,7 +109,7 @@ impl MdToken { let table_split = iter.next().unwrap(); let mut table_rows = Vec::new(); while let Some(peeked_row_line) = iter.peek() { - decreate_max_iterations(); + decrease_max_iterations(); if !peeked_row_line.contains('|') { // we've reached the end of the table, let's go back one step From b32311ae65e392b99b964befb8fcfdc41cd4e7cc Mon Sep 17 00:00:00 2001 From: Joel Wachsler Date: Sun, 17 Jul 2022 12:19:22 +0000 Subject: [PATCH 26/47] Extract table logic --- .../src/md_parser/md_token.rs | 129 +++++++++++------- 1 file changed, 83 insertions(+), 46 deletions(-) diff --git a/qbittorrent-web-api-gen/src/md_parser/md_token.rs b/qbittorrent-web-api-gen/src/md_parser/md_token.rs index 139c898..23bca7b 100644 --- a/qbittorrent-web-api-gen/src/md_parser/md_token.rs +++ b/qbittorrent-web-api-gen/src/md_parser/md_token.rs @@ -78,58 +78,18 @@ impl MdToken { pub fn from(content: &str) -> Vec { // to prevent infinite loops - let mut max_iterations = 10000; - let mut decrease_max_iterations = || { - max_iterations -= 1; - if max_iterations <= 0 { - panic!("Max iterations reached, missing termination?"); - }; - }; + let mut max_iterator_checker = MaxIteratorChecker::default(); let mut output = Vec::new(); - let mut iter = content.lines().peekable(); + while let Some(line) = iter.next() { - decrease_max_iterations(); + max_iterator_checker.decrease(); - // assume this is a table + // assume that lines starting with "|" are tables if line.contains('|') { - let to_columns = |column_line: &str| { - column_line - .replace('`', "") - .split('|') - .map(|s| s.trim().to_string()) - .collect() - }; - - let table_header = TableRow { - raw: line.into(), - columns: to_columns(line), - }; - let table_split = iter.next().unwrap(); - let mut table_rows = Vec::new(); - while let Some(peeked_row_line) = iter.peek() { - decrease_max_iterations(); - - if !peeked_row_line.contains('|') { - // we've reached the end of the table, let's go back one step - break; - } - - let next_row_line = iter.next().unwrap(); - let table_row = TableRow { - raw: next_row_line.to_string(), - columns: to_columns(next_row_line), - }; - - table_rows.push(table_row); - } - - output.push(MdToken::Content(MdContent::Table(Table { - header: table_header, - split: table_split.to_string(), - rows: table_rows, - }))); + let table = TableParser::new(&mut max_iterator_checker, &mut iter).parse(line); + output.push(MdToken::Content(table)); } else { output.push(MdToken::parse_token(line)); } @@ -138,3 +98,80 @@ impl MdToken { output } } + +struct TableParser<'a, 'b> { + max_iterator_checker: &'a mut MaxIteratorChecker, + iter: &'a mut std::iter::Peekable>, +} + +impl<'a, 'b> TableParser<'a, 'b> { + fn new( + max_iterator_checker: &'a mut MaxIteratorChecker, + iter: &'a mut std::iter::Peekable>, + ) -> Self { + Self { + max_iterator_checker, + iter, + } + } + + fn parse(&mut self, line: &str) -> MdContent { + let to_columns = |column_line: &str| { + column_line + .replace('`', "") + .split('|') + .map(|s| s.trim().to_string()) + .collect() + }; + + let table_header = TableRow { + raw: line.into(), + columns: to_columns(line), + }; + + let table_split = self.iter.next().unwrap(); + let mut table_rows = Vec::new(); + while let Some(peeked_row_line) = self.iter.peek() { + self.max_iterator_checker.decrease(); + + if !peeked_row_line.contains('|') { + // we've reached the end of the table, let's go back one step + break; + } + + let next_row_line = self.iter.next().unwrap(); + table_rows.push(TableRow { + raw: next_row_line.to_string(), + columns: to_columns(next_row_line), + }); + } + + MdContent::Table(Table { + header: table_header, + split: table_split.to_string(), + rows: table_rows, + }) + } +} + +#[derive(Debug)] +struct MaxIteratorChecker { + max_iterations: i32, +} + +impl MaxIteratorChecker { + fn decrease(&mut self) { + self.max_iterations -= 1; + if self.max_iterations <= 0 { + panic!("Max iterations reached, missing termination?"); + } + } +} + +impl Default for MaxIteratorChecker { + fn default() -> Self { + MaxIteratorChecker { + max_iterations: 10000, + } + } +} From 62ab77f4e8de9e6e99c670318fb129c1ebf49eb8 Mon Sep 17 00:00:00 2001 From: Joel Wachsler Date: Sun, 17 Jul 2022 12:24:14 +0000 Subject: [PATCH 27/47] Extract row parsing --- .../src/md_parser/md_token.rs | 37 +++++++++++-------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/qbittorrent-web-api-gen/src/md_parser/md_token.rs b/qbittorrent-web-api-gen/src/md_parser/md_token.rs index 23bca7b..ac3e62d 100644 --- a/qbittorrent-web-api-gen/src/md_parser/md_token.rs +++ b/qbittorrent-web-api-gen/src/md_parser/md_token.rs @@ -116,21 +116,24 @@ impl<'a, 'b> TableParser<'a, 'b> { } fn parse(&mut self, line: &str) -> MdContent { - let to_columns = |column_line: &str| { - column_line - .replace('`', "") - .split('|') - .map(|s| s.trim().to_string()) - .collect() - }; - let table_header = TableRow { raw: line.into(), - columns: to_columns(line), + columns: Self::to_columns(line), }; let table_split = self.iter.next().unwrap(); + let table_rows = self.table_rows(); + + MdContent::Table(Table { + header: table_header, + split: table_split.to_string(), + rows: table_rows, + }) + } + + fn table_rows(&mut self) -> Vec { let mut table_rows = Vec::new(); + while let Some(peeked_row_line) = self.iter.peek() { self.max_iterator_checker.decrease(); @@ -142,15 +145,19 @@ impl<'a, 'b> TableParser<'a, 'b> { let next_row_line = self.iter.next().unwrap(); table_rows.push(TableRow { raw: next_row_line.to_string(), - columns: to_columns(next_row_line), + columns: Self::to_columns(next_row_line), }); } - MdContent::Table(Table { - header: table_header, - split: table_split.to_string(), - rows: table_rows, - }) + table_rows + } + + fn to_columns(column_line: &str) -> Vec { + column_line + .replace('`', "") + .split('|') + .map(|s| s.trim().to_string()) + .collect() } } From cc9a67d680639e3a928ec2c5a7b9857630a676b8 Mon Sep 17 00:00:00 2001 From: Joel Wachsler Date: Sun, 17 Jul 2022 12:32:34 +0000 Subject: [PATCH 28/47] Move if one level up --- .../src/md_parser/md_token.rs | 46 +++++++++---------- 1 file changed, 21 insertions(+), 25 deletions(-) diff --git a/qbittorrent-web-api-gen/src/md_parser/md_token.rs b/qbittorrent-web-api-gen/src/md_parser/md_token.rs index ac3e62d..998a3cf 100644 --- a/qbittorrent-web-api-gen/src/md_parser/md_token.rs +++ b/qbittorrent-web-api-gen/src/md_parser/md_token.rs @@ -52,30 +52,6 @@ pub enum MdToken { } impl MdToken { - fn parse_token(line: &str) -> MdToken { - if line.starts_with('#') { - let mut level = 0; - for char in line.chars() { - if char != '#' { - break; - } - - level += 1; - } - - MdToken::Header(Header { - level, - content: line.trim_matches('#').trim().to_string(), - }) - } else if line.starts_with('*') { - MdToken::Content(MdContent::Asterisk( - line.trim_matches('*').trim().to_string(), - )) - } else { - MdToken::Content(MdContent::Text(line.to_string())) - } - } - pub fn from(content: &str) -> Vec { // to prevent infinite loops let mut max_iterator_checker = MaxIteratorChecker::default(); @@ -90,8 +66,13 @@ impl MdToken { if line.contains('|') { let table = TableParser::new(&mut max_iterator_checker, &mut iter).parse(line); output.push(MdToken::Content(table)); + } else if line.starts_with('#') { + output.push(parse_header(line)); + } else if line.starts_with('*') { + let asterisk = MdContent::Asterisk(line.trim_matches('*').trim().to_string()); + output.push(MdToken::Content(asterisk)); } else { - output.push(MdToken::parse_token(line)); + output.push(MdToken::Content(MdContent::Text(line.to_string()))); } } @@ -99,6 +80,21 @@ impl MdToken { } } +fn parse_header(line: &str) -> MdToken { + let mut level = 0; + for char in line.chars() { + if char != '#' { + break; + } + + level += 1; + } + MdToken::Header(Header { + level, + content: line.trim_matches('#').trim().to_string(), + }) +} + struct TableParser<'a, 'b> { max_iterator_checker: &'a mut MaxIteratorChecker, iter: &'a mut std::iter::Peekable>, From c956fff004ed95873e8e9ae0f8a4a2231efcac42 Mon Sep 17 00:00:00 2001 From: Joel Wachsler Date: Sun, 17 Jul 2022 20:32:27 +0000 Subject: [PATCH 29/47] Add object array ref types --- qbittorrent-web-api-gen/groups.txt | 21 +++++---- qbittorrent-web-api-gen/src/types.rs | 66 ++++++++++++++++++++++++---- 2 files changed, 69 insertions(+), 18 deletions(-) diff --git a/qbittorrent-web-api-gen/groups.txt b/qbittorrent-web-api-gen/groups.txt index e34dc7b..260224e 100644 --- a/qbittorrent-web-api-gen/groups.txt +++ b/qbittorrent-web-api-gen/groups.txt @@ -5852,15 +5852,18 @@ ReturnTypeParameter { name: "results", description: "Array of result objects- see table below", - return_type: StringArray( - TypeInfo { - name: "results", - is_optional: false, - is_list: false, - description: Some( - "Array of result objects- see table below", - ), - type_description: None, + return_type: ObjectArray( + TypeWithRef { + type_info: TypeInfo { + name: "results", + is_optional: false, + is_list: false, + description: Some( + "Array of result objects- see table below", + ), + type_description: None, + }, + ref_type: "result", }, ), }, diff --git a/qbittorrent-web-api-gen/src/types.rs b/qbittorrent-web-api-gen/src/types.rs index 722c5f9..5f49d9d 100644 --- a/qbittorrent-web-api-gen/src/types.rs +++ b/qbittorrent-web-api-gen/src/types.rs @@ -1,3 +1,4 @@ +use regex::RegexBuilder; use std::collections::HashMap; #[derive(Debug, Clone)] @@ -38,6 +39,12 @@ impl TypeInfo { } } +#[derive(Debug, Clone)] +pub struct TypeWithRef { + pub type_info: TypeInfo, + pub ref_type: String, +} + pub const OPTIONAL: &str = "_optional_"; #[derive(Debug, Clone)] @@ -47,6 +54,7 @@ pub enum Type { Bool(TypeInfo), String(TypeInfo), StringArray(TypeInfo), + ObjectArray(TypeWithRef), Object(TypeInfo), } @@ -57,9 +65,9 @@ impl Type { Type::Float(_) => "f32".into(), Type::Bool(_) => "bool".into(), Type::String(_) => "String".into(), - // TODO: fixme Type::StringArray(_) => "String".into(), Type::Object(_) => "String".into(), + Type::ObjectArray(_) => panic!("Not implemented for ObjectArray"), } } @@ -75,6 +83,7 @@ impl Type { Type::String(_) => "str".into(), Type::StringArray(_) => "&[str]".into(), Type::Object(_) => "str".into(), + Type::ObjectArray(_) => panic!("Not implemented for ObjectArray"), } } @@ -90,6 +99,7 @@ impl Type { Type::String(t) => t, Type::StringArray(t) => t, Type::Object(t) => t, + Type::ObjectArray(TypeWithRef { type_info, .. }) => type_info, } } @@ -107,17 +117,55 @@ impl Type { .trim(); let is_optional = name.contains(OPTIONAL); - let type_info = TypeInfo::new(type_name, is_optional, false, description, available_types); + let create_type_info = || { + TypeInfo::new( + type_name, + is_optional, + false, + description.clone(), + available_types.clone(), + ) + }; match type_as_str { - "bool" => Some(Type::Bool(type_info)), - "integer" | "number" | "int" => Some(Type::Number(type_info)), - "string" => Some(Type::String(type_info)), - // This is probably not right but we don't have any information about the actual type. - "array" => Some(Type::StringArray(type_info)), - "object" => Some(Type::Object(type_info)), - "float" => Some(Type::Float(type_info)), + "bool" => Some(Type::Bool(create_type_info())), + "integer" | "number" | "int" => Some(Type::Number(create_type_info())), + "string" => Some(Type::String(create_type_info())), + "array" => description + .clone() + .and_then(|ref desc| get_ref_type(desc)) + .map(|ref_type| { + Type::ObjectArray(TypeWithRef { + type_info: create_type_info(), + ref_type, + }) + }) + .or_else(|| Some(Type::StringArray(create_type_info()))), + "object" => Some(Type::Object(create_type_info())), + "float" => Some(Type::Float(create_type_info())), _ => None, } } } + +fn get_ref_type(desc: &str) -> Option { + let re = RegexBuilder::new(r".*array of (\w+)\s?.*") + .case_insensitive(true) + .build() + .unwrap(); + + re.captures(desc) + .and_then(|captures| captures.get(1)) + .map(|m| m.as_str().to_owned()) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn should_parse_object_array() { + let ref_type = get_ref_type("Array of result objects- see table below"); + assert_eq!("result", ref_type.unwrap()); + } +} From e58db20e218ee6590fc22f9fbfb6db2e216d0f9c Mon Sep 17 00:00:00 2001 From: Joel Wachsler Date: Sun, 17 Jul 2022 20:42:20 +0000 Subject: [PATCH 30/47] Extract variable --- .../src/md_parser/token_tree_factory.rs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/qbittorrent-web-api-gen/src/md_parser/token_tree_factory.rs b/qbittorrent-web-api-gen/src/md_parser/token_tree_factory.rs index ad170ff..d75aa64 100644 --- a/qbittorrent-web-api-gen/src/md_parser/token_tree_factory.rs +++ b/qbittorrent-web-api-gen/src/md_parser/token_tree_factory.rs @@ -73,20 +73,25 @@ impl TokenTreeFactory { mod tests { use super::*; + macro_rules! TEST_DIR { + () => { + "token_tree_factory_tests" + }; + } + macro_rules! run_test { ($test_file:expr) => { use pretty_assertions::assert_eq; // given - let input = include_str!(concat!("token_tree_factory_tests/", $test_file, ".md")); + let input = include_str!(concat!(TEST_DIR!(), "/", $test_file, ".md")); // when let tree = TokenTreeFactory::create(input); // then let tree_as_str = format!("{tree:#?}"); - let should_be = - include_str!(concat!("token_tree_factory_tests/", $test_file, ".check")); + let should_be = include_str!(concat!(TEST_DIR!(), "/", $test_file, ".check")); assert_eq!(tree_as_str, should_be); }; } @@ -98,12 +103,12 @@ mod tests { use std::fs; use std::path::Path; - let input = include_str!(concat!("token_tree_factory_tests/", $test_file, ".md")); + let input = include_str!(concat!(TEST_DIR!(), "/", $test_file, ".md")); let tree = TokenTreeFactory::create(input); let tree_as_str = format!("{tree:#?}"); - let file = concat!("src/md_parser/token_tree_factory_tests/", $test_file, ".check"); + let file = concat!("src/md_parser/", TEST_DIR!(), "/", $test_file, ".check"); - // prevent user from accidentially leaving the current macro in a test + // prevent user from accidentally leaving the current macro in a test if Path::new(file).exists() { panic!("Test case already exists: {file}"); } From 8db9faf5f08e42764308b43f5a228e5d67b02a59 Mon Sep 17 00:00:00 2001 From: Joel Wachsler Date: Tue, 19 Jul 2022 10:26:17 +0000 Subject: [PATCH 31/47] Fix table parsing --- qbittorrent-web-api-gen/groups.txt | 21 +- .../src/md_parser/md_token.rs | 3 +- .../src/md_parser/token_tree_factory.rs | 5 + .../non_table_with_pipe.check | 17 + .../non_table_with_pipe.md | 2 + qbittorrent-web-api-gen/token_tree.txt | 560 ++++++------------ 6 files changed, 193 insertions(+), 415 deletions(-) create mode 100644 qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/non_table_with_pipe.check create mode 100644 qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/non_table_with_pipe.md diff --git a/qbittorrent-web-api-gen/groups.txt b/qbittorrent-web-api-gen/groups.txt index 260224e..88f9685 100644 --- a/qbittorrent-web-api-gen/groups.txt +++ b/qbittorrent-web-api-gen/groups.txt @@ -2983,7 +2983,7 @@ ApiMethod { name: "info", description: Some( - "The response is a JSON object with the following fields\n\n\nIn addition to the above in partial data requests (see [Get partial data](#get-partial-data) for more info):\n\n\nPossible values of `connection_status`:\n\n\nExample:\n\n```JSON\n{\n \"connection_status\":\"connected\",\n \"dht_nodes\":386,\n \"dl_info_data\":681521119,\n \"dl_info_speed\":0,\n \"dl_rate_limit\":0,\n \"up_info_data\":10747904,\n \"up_info_speed\":0,\n \"up_rate_limit\":1048576\n}\n```", + "The response is a JSON object with the following fields\n\n\nIn addition to the above in partial data requests (see [Get partial data](#get-partial-data) for more info):\n\n\nPossible values of `connection_status`:\n\nValue |\n\nExample:\n\n```JSON\n{\n \"connection_status\":\"connected\",\n \"dht_nodes\":386,\n \"dl_info_data\":681521119,\n \"dl_info_speed\":0,\n \"dl_rate_limit\":0,\n \"up_info_data\":10747904,\n \"up_info_speed\":0,\n \"up_rate_limit\":1048576\n}\n```", ), parameters: None, return_type: Some( @@ -3106,24 +3106,7 @@ description: Some( "Connection status. See possible values here below", ), - type_description: Some( - TypeDescription { - values: [ - TypeDescriptions { - value: "connected", - description: "", - }, - TypeDescriptions { - value: "firewalled", - description: "", - }, - TypeDescriptions { - value: "disconnected", - description: "", - }, - ], - }, - ), + type_description: None, }, ), }, diff --git a/qbittorrent-web-api-gen/src/md_parser/md_token.rs b/qbittorrent-web-api-gen/src/md_parser/md_token.rs index 998a3cf..3b1d181 100644 --- a/qbittorrent-web-api-gen/src/md_parser/md_token.rs +++ b/qbittorrent-web-api-gen/src/md_parser/md_token.rs @@ -62,8 +62,7 @@ impl MdToken { while let Some(line) = iter.next() { max_iterator_checker.decrease(); - // assume that lines starting with "|" are tables - if line.contains('|') { + if line.contains(" | ") || line.contains("-|") || line.contains("|-") { let table = TableParser::new(&mut max_iterator_checker, &mut iter).parse(line); output.push(MdToken::Content(table)); } else if line.starts_with('#') { diff --git a/qbittorrent-web-api-gen/src/md_parser/token_tree_factory.rs b/qbittorrent-web-api-gen/src/md_parser/token_tree_factory.rs index d75aa64..acff043 100644 --- a/qbittorrent-web-api-gen/src/md_parser/token_tree_factory.rs +++ b/qbittorrent-web-api-gen/src/md_parser/token_tree_factory.rs @@ -146,4 +146,9 @@ mod tests { fn multi_table() { run_test!("multi_table"); } + + #[test] + fn non_table_with_pipe() { + run_test!("non_table_with_pipe"); + } } diff --git a/qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/non_table_with_pipe.check b/qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/non_table_with_pipe.check new file mode 100644 index 0000000..502d25d --- /dev/null +++ b/qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/non_table_with_pipe.check @@ -0,0 +1,17 @@ +TokenTree { + title: None, + content: [], + children: [ + TokenTree { + title: Some( + "A", + ), + content: [ + Text( + "a|b", + ), + ], + children: [], + }, + ], +} \ No newline at end of file diff --git a/qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/non_table_with_pipe.md b/qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/non_table_with_pipe.md new file mode 100644 index 0000000..7087e40 --- /dev/null +++ b/qbittorrent-web-api-gen/src/md_parser/token_tree_factory_tests/non_table_with_pipe.md @@ -0,0 +1,2 @@ +# A +a|b \ No newline at end of file diff --git a/qbittorrent-web-api-gen/token_tree.txt b/qbittorrent-web-api-gen/token_tree.txt index 2828f1c..46c7841 100644 --- a/qbittorrent-web-api-gen/token_tree.txt +++ b/qbittorrent-web-api-gen/token_tree.txt @@ -4972,24 +4972,20 @@ TokenTree { Text( "", ), + Text( + "Value |", + ), Table( Table { header: TableRow { - raw: "Value |", + raw: "--------------------|", columns: [ - "Value", + "--------------------", "", ], }, - split: "--------------------|", + split: "`connected` |", rows: [ - TableRow { - raw: "`connected` |", - columns: [ - "connected", - "", - ], - }, TableRow { raw: "`firewalled` |", columns: [ @@ -7981,18 +7977,11 @@ TokenTree { Text( "```http", ), - Table( - Table { - header: TableRow { - raw: "/api/v2/torrents/pause?hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|54eddd830a5b58480a6143d616a97e3a6c23c439", - columns: [ - "/api/v2/torrents/pause?hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32", - "54eddd830a5b58480a6143d616a97e3a6c23c439", - ], - }, - split: "```", - rows: [], - }, + Text( + "/api/v2/torrents/pause?hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|54eddd830a5b58480a6143d616a97e3a6c23c439", + ), + Text( + "```", ), Text( "", @@ -8092,18 +8081,11 @@ TokenTree { Text( "```http", ), - Table( - Table { - header: TableRow { - raw: "/api/v2/torrents/resume?hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|54eddd830a5b58480a6143d616a97e3a6c23c439", - columns: [ - "/api/v2/torrents/resume?hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32", - "54eddd830a5b58480a6143d616a97e3a6c23c439", - ], - }, - split: "```", - rows: [], - }, + Text( + "/api/v2/torrents/resume?hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|54eddd830a5b58480a6143d616a97e3a6c23c439", + ), + Text( + "```", ), Text( "", @@ -8314,18 +8296,11 @@ TokenTree { Text( "```http", ), - Table( - Table { - header: TableRow { - raw: "/api/v2/torrents/recheck?hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|54eddd830a5b58480a6143d616a97e3a6c23c439", - columns: [ - "/api/v2/torrents/recheck?hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32", - "54eddd830a5b58480a6143d616a97e3a6c23c439", - ], - }, - split: "```", - rows: [], - }, + Text( + "/api/v2/torrents/recheck?hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|54eddd830a5b58480a6143d616a97e3a6c23c439", + ), + Text( + "```", ), Text( "", @@ -8425,18 +8400,11 @@ TokenTree { Text( "```http", ), - Table( - Table { - header: TableRow { - raw: "/api/v2/torrents/reannounce?hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|54eddd830a5b58480a6143d616a97e3a6c23c439", - columns: [ - "/api/v2/torrents/reannounce?hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32", - "54eddd830a5b58480a6143d616a97e3a6c23c439", - ], - }, - split: "```", - rows: [], - }, + Text( + "/api/v2/torrents/reannounce?hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|54eddd830a5b58480a6143d616a97e3a6c23c439", + ), + Text( + "```", ), Text( "", @@ -9380,18 +9348,11 @@ TokenTree { Text( "```http", ), - Table( - Table { - header: TableRow { - raw: "/api/v2/torrents/increasePrio?hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|54eddd830a5b58480a6143d616a97e3a6c23c439", - columns: [ - "/api/v2/torrents/increasePrio?hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32", - "54eddd830a5b58480a6143d616a97e3a6c23c439", - ], - }, - split: "```", - rows: [], - }, + Text( + "/api/v2/torrents/increasePrio?hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|54eddd830a5b58480a6143d616a97e3a6c23c439", + ), + Text( + "```", ), Text( "", @@ -9498,18 +9459,11 @@ TokenTree { Text( "```http", ), - Table( - Table { - header: TableRow { - raw: "/api/v2/torrents/decreasePrio?hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|54eddd830a5b58480a6143d616a97e3a6c23c439", - columns: [ - "/api/v2/torrents/decreasePrio?hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32", - "54eddd830a5b58480a6143d616a97e3a6c23c439", - ], - }, - split: "```", - rows: [], - }, + Text( + "/api/v2/torrents/decreasePrio?hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|54eddd830a5b58480a6143d616a97e3a6c23c439", + ), + Text( + "```", ), Text( "", @@ -9616,18 +9570,11 @@ TokenTree { Text( "```http", ), - Table( - Table { - header: TableRow { - raw: "/api/v2/torrents/topPrio?hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|54eddd830a5b58480a6143d616a97e3a6c23c439", - columns: [ - "/api/v2/torrents/topPrio?hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32", - "54eddd830a5b58480a6143d616a97e3a6c23c439", - ], - }, - split: "```", - rows: [], - }, + Text( + "/api/v2/torrents/topPrio?hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|54eddd830a5b58480a6143d616a97e3a6c23c439", + ), + Text( + "```", ), Text( "", @@ -9734,18 +9681,11 @@ TokenTree { Text( "```http", ), - Table( - Table { - header: TableRow { - raw: "/api/v2/torrents/bottomPrio?hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|54eddd830a5b58480a6143d616a97e3a6c23c439", - columns: [ - "/api/v2/torrents/bottomPrio?hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32", - "54eddd830a5b58480a6143d616a97e3a6c23c439", - ], - }, - split: "```", - rows: [], - }, + Text( + "/api/v2/torrents/bottomPrio?hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|54eddd830a5b58480a6143d616a97e3a6c23c439", + ), + Text( + "```", ), Text( "", @@ -9977,34 +9917,20 @@ TokenTree { Text( "", ), - Table( - Table { - header: TableRow { - raw: "hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|284b83c9c7935002391129fd97f43db5d7cc2ba0", - columns: [ - "hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32", - "284b83c9c7935002391129fd97f43db5d7cc2ba0", - ], - }, - split: "```", - rows: [], - }, + Text( + "hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|284b83c9c7935002391129fd97f43db5d7cc2ba0", + ), + Text( + "```", ), Text( "", ), - Table( - Table { - header: TableRow { - raw: "`hashes` can contain multiple hashes separated by `|` or set to `all`", - columns: [ - "hashes can contain multiple hashes separated by", - "or set to all", - ], - }, - split: "", - rows: [], - }, + Text( + "`hashes` can contain multiple hashes separated by `|` or set to `all`", + ), + Text( + "", ), Text( "Server reply (example):", @@ -10083,34 +10009,20 @@ TokenTree { Text( "", ), - Table( - Table { - header: TableRow { - raw: "hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|284b83c9c7935002391129fd97f43db5d7cc2ba0&limit=131072", - columns: [ - "hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32", - "284b83c9c7935002391129fd97f43db5d7cc2ba0&limit=131072", - ], - }, - split: "```", - rows: [], - }, + Text( + "hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|284b83c9c7935002391129fd97f43db5d7cc2ba0&limit=131072", + ), + Text( + "```", ), Text( "", ), - Table( - Table { - header: TableRow { - raw: "`hashes` can contain multiple hashes separated by `|` or set to `all`", - columns: [ - "hashes can contain multiple hashes separated by", - "or set to all", - ], - }, - split: "`limit` is the download speed limit in bytes per second you want to set.", - rows: [], - }, + Text( + "`hashes` can contain multiple hashes separated by `|` or set to `all`", + ), + Text( + "`limit` is the download speed limit in bytes per second you want to set.", ), Text( "", @@ -10192,34 +10104,20 @@ TokenTree { Text( "", ), - Table( - Table { - header: TableRow { - raw: "hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|284b83c9c7935002391129fd97f43db5d7cc2ba0&ratioLimit=1.0&seedingTimeLimit=60", - columns: [ - "hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32", - "284b83c9c7935002391129fd97f43db5d7cc2ba0&ratioLimit=1.0&seedingTimeLimit=60", - ], - }, - split: "```", - rows: [], - }, + Text( + "hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|284b83c9c7935002391129fd97f43db5d7cc2ba0&ratioLimit=1.0&seedingTimeLimit=60", + ), + Text( + "```", ), Text( "", ), - Table( - Table { - header: TableRow { - raw: "`hashes` can contain multiple hashes separated by `|` or set to `all`", - columns: [ - "hashes can contain multiple hashes separated by", - "or set to all", - ], - }, - split: "`ratioLimit` is the max ratio the torrent should be seeded until. `-2` means the global limit should be used, `-1` means no limit.", - rows: [], - }, + Text( + "`hashes` can contain multiple hashes separated by `|` or set to `all`", + ), + Text( + "`ratioLimit` is the max ratio the torrent should be seeded until. `-2` means the global limit should be used, `-1` means no limit.", ), Text( "`seedingTimeLimit` is the max amount of time the torrent should be seeded. `-2` means the global limit should be used, `-1` means no limit.", @@ -10304,34 +10202,20 @@ TokenTree { Text( "", ), - Table( - Table { - header: TableRow { - raw: "hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|284b83c9c7935002391129fd97f43db5d7cc2ba0", - columns: [ - "hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32", - "284b83c9c7935002391129fd97f43db5d7cc2ba0", - ], - }, - split: "```", - rows: [], - }, + Text( + "hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|284b83c9c7935002391129fd97f43db5d7cc2ba0", + ), + Text( + "```", ), Text( "", ), - Table( - Table { - header: TableRow { - raw: "`hashes` can contain multiple hashes separated by `|` or set to `all`", - columns: [ - "hashes can contain multiple hashes separated by", - "or set to all", - ], - }, - split: "", - rows: [], - }, + Text( + "`hashes` can contain multiple hashes separated by `|` or set to `all`", + ), + Text( + "", ), Text( "Server reply (example):", @@ -10416,34 +10300,20 @@ TokenTree { Text( "", ), - Table( - Table { - header: TableRow { - raw: "hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|284b83c9c7935002391129fd97f43db5d7cc2ba0&limit=131072", - columns: [ - "hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32", - "284b83c9c7935002391129fd97f43db5d7cc2ba0&limit=131072", - ], - }, - split: "```", - rows: [], - }, + Text( + "hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|284b83c9c7935002391129fd97f43db5d7cc2ba0&limit=131072", + ), + Text( + "```", ), Text( "", ), - Table( - Table { - header: TableRow { - raw: "`hashes` can contain multiple hashes separated by `|` or set to `all`", - columns: [ - "hashes can contain multiple hashes separated by", - "or set to all", - ], - }, - split: "`limit` is the upload speed limit in bytes per second you want to set.", - rows: [], - }, + Text( + "`hashes` can contain multiple hashes separated by `|` or set to `all`", + ), + Text( + "`limit` is the upload speed limit in bytes per second you want to set.", ), Text( "", @@ -10525,34 +10395,20 @@ TokenTree { Text( "", ), - Table( - Table { - header: TableRow { - raw: "hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|284b83c9c7935002391129fd97f43db5d7cc2ba0&location=/mnt/nfs/media", - columns: [ - "hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32", - "284b83c9c7935002391129fd97f43db5d7cc2ba0&location=/mnt/nfs/media", - ], - }, - split: "```", - rows: [], - }, + Text( + "hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|284b83c9c7935002391129fd97f43db5d7cc2ba0&location=/mnt/nfs/media", + ), + Text( + "```", ), Text( "", ), - Table( - Table { - header: TableRow { - raw: "`hashes` can contain multiple hashes separated by `|` or set to `all`", - columns: [ - "hashes can contain multiple hashes separated by", - "or set to all", - ], - }, - split: "`location` is the location to download the torrent to. If the location doesn't exist, the torrent's location is unchanged.", - rows: [], - }, + Text( + "`hashes` can contain multiple hashes separated by `|` or set to `all`", + ), + Text( + "`location` is the location to download the torrent to. If the location doesn't exist, the torrent's location is unchanged.", ), Text( "", @@ -10755,34 +10611,20 @@ TokenTree { Text( "", ), - Table( - Table { - header: TableRow { - raw: "hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|284b83c9c7935002391129fd97f43db5d7cc2ba0&category=CategoryName", - columns: [ - "hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32", - "284b83c9c7935002391129fd97f43db5d7cc2ba0&category=CategoryName", - ], - }, - split: "```", - rows: [], - }, + Text( + "hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|284b83c9c7935002391129fd97f43db5d7cc2ba0&category=CategoryName", + ), + Text( + "```", ), Text( "", ), - Table( - Table { - header: TableRow { - raw: "`hashes` can contain multiple hashes separated by `|` or set to `all`", - columns: [ - "hashes can contain multiple hashes separated by", - "or set to all", - ], - }, - split: "", - rows: [], - }, + Text( + "`hashes` can contain multiple hashes separated by `|` or set to `all`", + ), + Text( + "", ), Text( "`category` is the torrent category you want to set.", @@ -11255,34 +11097,20 @@ TokenTree { Text( "", ), - Table( - Table { - header: TableRow { - raw: "hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|284b83c9c7935002391129fd97f43db5d7cc2ba0&tags=TagName1,TagName2", - columns: [ - "hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32", - "284b83c9c7935002391129fd97f43db5d7cc2ba0&tags=TagName1,TagName2", - ], - }, - split: "```", - rows: [], - }, + Text( + "hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|284b83c9c7935002391129fd97f43db5d7cc2ba0&tags=TagName1,TagName2", + ), + Text( + "```", ), Text( "", ), - Table( - Table { - header: TableRow { - raw: "`hashes` can contain multiple hashes separated by `|` or set to `all`", - columns: [ - "hashes can contain multiple hashes separated by", - "or set to all", - ], - }, - split: "", - rows: [], - }, + Text( + "`hashes` can contain multiple hashes separated by `|` or set to `all`", + ), + Text( + "", ), Text( "`tags` is the list of tags you want to add to passed torrents.", @@ -11367,34 +11195,20 @@ TokenTree { Text( "", ), - Table( - Table { - header: TableRow { - raw: "hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|284b83c9c7935002391129fd97f43db5d7cc2ba0&tags=TagName1,TagName2", - columns: [ - "hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32", - "284b83c9c7935002391129fd97f43db5d7cc2ba0&tags=TagName1,TagName2", - ], - }, - split: "```", - rows: [], - }, + Text( + "hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|284b83c9c7935002391129fd97f43db5d7cc2ba0&tags=TagName1,TagName2", + ), + Text( + "```", ), Text( "", ), - Table( - Table { - header: TableRow { - raw: "`hashes` can contain multiple hashes separated by `|` or set to `all`", - columns: [ - "hashes can contain multiple hashes separated by", - "or set to all", - ], - }, - split: "", - rows: [], - }, + Text( + "`hashes` can contain multiple hashes separated by `|` or set to `all`", + ), + Text( + "", ), Text( "`tags` is the list of tags you want to remove from passed torrents.", @@ -11740,34 +11554,20 @@ TokenTree { Text( "", ), - Table( - Table { - header: TableRow { - raw: "hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|284b83c9c7935002391129fd97f43db5d7cc2ba0&enable=true", - columns: [ - "hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32", - "284b83c9c7935002391129fd97f43db5d7cc2ba0&enable=true", - ], - }, - split: "```", - rows: [], - }, + Text( + "hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|284b83c9c7935002391129fd97f43db5d7cc2ba0&enable=true", + ), + Text( + "```", ), Text( "", ), - Table( - Table { - header: TableRow { - raw: "`hashes` can contain multiple hashes separated by `|` or set to `all`", - columns: [ - "hashes can contain multiple hashes separated by", - "or set to all", - ], - }, - split: "`enable` is a boolean, affects the torrents listed in `hashes`, default is `false`", - rows: [], - }, + Text( + "`hashes` can contain multiple hashes separated by `|` or set to `all`", + ), + Text( + "`enable` is a boolean, affects the torrents listed in `hashes`, default is `false`", ), Text( "", @@ -11867,18 +11667,11 @@ TokenTree { Text( "```http", ), - Table( - Table { - header: TableRow { - raw: "/api/v2/torrents/toggleSequentialDownload?hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|54eddd830a5b58480a6143d616a97e3a6c23c439", - columns: [ - "/api/v2/torrents/toggleSequentialDownload?hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32", - "54eddd830a5b58480a6143d616a97e3a6c23c439", - ], - }, - split: "```", - rows: [], - }, + Text( + "/api/v2/torrents/toggleSequentialDownload?hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|54eddd830a5b58480a6143d616a97e3a6c23c439", + ), + Text( + "```", ), Text( "", @@ -11978,18 +11771,11 @@ TokenTree { Text( "```http", ), - Table( - Table { - header: TableRow { - raw: "/api/v2/torrents/toggleFirstLastPiecePrio?hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|54eddd830a5b58480a6143d616a97e3a6c23c439", - columns: [ - "/api/v2/torrents/toggleFirstLastPiecePrio?hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32", - "54eddd830a5b58480a6143d616a97e3a6c23c439", - ], - }, - split: "```", - rows: [], - }, + Text( + "/api/v2/torrents/toggleFirstLastPiecePrio?hashes=8c212779b4abde7c6bc608063a0d008b7e40ce32|54eddd830a5b58480a6143d616a97e3a6c23c439", + ), + Text( + "```", ), Text( "", @@ -12080,18 +11866,11 @@ TokenTree { Text( "", ), - Table( - Table { - header: TableRow { - raw: "`hashes` can contain multiple hashes separated by `|` or set to `all`", - columns: [ - "hashes can contain multiple hashes separated by", - "or set to all", - ], - }, - split: "`value` is a boolean, affects the torrents listed in `hashes`, default is `false`", - rows: [], - }, + Text( + "`hashes` can contain multiple hashes separated by `|` or set to `all`", + ), + Text( + "`value` is a boolean, affects the torrents listed in `hashes`, default is `false`", ), Text( "", @@ -12182,18 +11961,11 @@ TokenTree { Text( "", ), - Table( - Table { - header: TableRow { - raw: "`hashes` can contain multiple hashes separated by `|` or set to `all`", - columns: [ - "hashes can contain multiple hashes separated by", - "or set to all", - ], - }, - split: "`value` is a boolean, affects the torrents listed in `hashes`, default is `false`", - rows: [], - }, + Text( + "`hashes` can contain multiple hashes separated by `|` or set to `all`", + ), + Text( + "`value` is a boolean, affects the torrents listed in `hashes`, default is `false`", ), Text( "", From a72d3e5fa7783393bd87c55df375bc2ce441509e Mon Sep 17 00:00:00 2001 From: Joel Wachsler Date: Tue, 19 Jul 2022 10:37:46 +0000 Subject: [PATCH 32/47] Move parameter parsing to associated methods --- qbittorrent-web-api-gen/groups.txt | 21 +- .../method/method_tests/search_result.check | 100 ++++++ .../method/method_tests/search_result.md | 68 ++++ .../method/method_tests/search_result.tree | 327 ++++++++++++++++++ .../src/parser/group/method/mod.rs | 158 ++++++++- .../src/parser/group/method/parameters.rs | 51 --- qbittorrent-web-api-gen/src/types.rs | 66 ++-- 7 files changed, 694 insertions(+), 97 deletions(-) create mode 100644 qbittorrent-web-api-gen/src/parser/group/method/method_tests/search_result.check create mode 100644 qbittorrent-web-api-gen/src/parser/group/method/method_tests/search_result.md create mode 100644 qbittorrent-web-api-gen/src/parser/group/method/method_tests/search_result.tree delete mode 100644 qbittorrent-web-api-gen/src/parser/group/method/parameters.rs diff --git a/qbittorrent-web-api-gen/groups.txt b/qbittorrent-web-api-gen/groups.txt index 88f9685..c32ae2f 100644 --- a/qbittorrent-web-api-gen/groups.txt +++ b/qbittorrent-web-api-gen/groups.txt @@ -5835,18 +5835,15 @@ ReturnTypeParameter { name: "results", description: "Array of result objects- see table below", - return_type: ObjectArray( - TypeWithRef { - type_info: TypeInfo { - name: "results", - is_optional: false, - is_list: false, - description: Some( - "Array of result objects- see table below", - ), - type_description: None, - }, - ref_type: "result", + return_type: StringArray( + TypeInfo { + name: "results", + is_optional: false, + is_list: false, + description: Some( + "Array of result objects- see table below", + ), + type_description: None, }, ), }, diff --git a/qbittorrent-web-api-gen/src/parser/group/method/method_tests/search_result.check b/qbittorrent-web-api-gen/src/parser/group/method/method_tests/search_result.check new file mode 100644 index 0000000..5609adf --- /dev/null +++ b/qbittorrent-web-api-gen/src/parser/group/method/method_tests/search_result.check @@ -0,0 +1,100 @@ +ApiMethod { + name: "results", + description: Some( + "The response is a JSON object with the following fields\n\n\n\n\nExample:\n\n```JSON\n{\n \"results\": [\n {\n \"descrLink\": \"http://www.legittorrents.info/index.php?page=torrent-details&id=8d5f512e1acb687029b8d7cc6c5a84dce51d7a41\",\n \"fileName\": \"Ubuntu-10.04-32bit-NeTV.ova\",\n \"fileSize\": -1,\n \"fileUrl\": \"http://www.legittorrents.info/download.php?id=8d5f512e1acb687029b8d7cc6c5a84dce51d7a41&f=Ubuntu-10.04-32bit-NeTV.ova.torrent\",\n \"nbLeechers\": 1,\n \"nbSeeders\": 0,\n \"siteUrl\": \"http://www.legittorrents.info\"\n },\n {\n \"descrLink\": \"http://www.legittorrents.info/index.php?page=torrent-details&id=d5179f53e105dc2c2401bcfaa0c2c4936a6aa475\",\n \"fileName\": \"mangOH-Legato-17_06-Ubuntu-16_04.ova\",\n \"fileSize\": -1,\n \"fileUrl\": \"http://www.legittorrents.info/download.php?id=d5179f53e105dc2c2401bcfaa0c2c4936a6aa475&f=mangOH-Legato-17_06-Ubuntu-16_04.ova.torrent\",\n \"nbLeechers\": 0,\n \"nbSeeders\": 59,\n \"siteUrl\": \"http://www.legittorrents.info\"\n }\n ],\n \"status\": \"Running\",\n \"total\": 2\n}\n```", + ), + parameters: Some( + ApiParameters { + mandatory: [ + Number( + TypeInfo { + name: "id", + is_optional: false, + is_list: false, + description: Some( + "ID of the search job", + ), + type_description: None, + }, + ), + ], + optional: [ + Number( + TypeInfo { + name: "limit", + is_optional: true, + is_list: false, + description: Some( + "max number of results to return. 0 or negative means no limit", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "offset", + is_optional: true, + is_list: false, + description: Some( + "result to start at. A negative number means count backwards (e.g. -2 returns the 2 most recent results)", + ), + type_description: None, + }, + ), + ], + }, + ), + return_type: Some( + ReturnType { + is_list: false, + parameters: [ + ReturnTypeParameter { + name: "results", + description: "Array of result objects- see table below", + return_type: StringArray( + TypeInfo { + name: "results", + is_optional: false, + is_list: false, + description: Some( + "Array of result objects- see table below", + ), + type_description: None, + }, + ), + }, + ReturnTypeParameter { + name: "status", + description: "Current status of the search job (either Running or Stopped)", + return_type: String( + TypeInfo { + name: "status", + is_optional: false, + is_list: false, + description: Some( + "Current status of the search job (either Running or Stopped)", + ), + type_description: None, + }, + ), + }, + ReturnTypeParameter { + name: "total", + description: "Total number of results. If the status is Running this number may continue to increase", + return_type: Number( + TypeInfo { + name: "total", + is_optional: false, + is_list: false, + description: Some( + "Total number of results. If the status is Running this number may continue to increase", + ), + type_description: None, + }, + ), + }, + ], + }, + ), + url: "results", +} \ No newline at end of file diff --git a/qbittorrent-web-api-gen/src/parser/group/method/method_tests/search_result.md b/qbittorrent-web-api-gen/src/parser/group/method/method_tests/search_result.md new file mode 100644 index 0000000..6ef3347 --- /dev/null +++ b/qbittorrent-web-api-gen/src/parser/group/method/method_tests/search_result.md @@ -0,0 +1,68 @@ +## Get search results ## + +Name: `results` + +**Parameters:** + +Parameter | Type | Description +----------------------------------|---------|------------ +`id` | number | ID of the search job +`limit` _optional_ | number | max number of results to return. 0 or negative means no limit +`offset` _optional_ | number | result to start at. A negative number means count backwards (e.g. `-2` returns the 2 most recent results) + +**Returns:** + +HTTP Status Code | Scenario +----------------------------------|--------------------- +404 | Search job was not found +409 | Offset is too large, or too small (e.g. absolute value of negative number is greater than # results) +200 | All other scenarios- see JSON below + +The response is a JSON object with the following fields + +Field | Type | Description +----------------------------------|---------|------------ +`results` | array | Array of `result` objects- see table below +`status` | string | Current status of the search job (either `Running` or `Stopped`) +`total` | number | Total number of results. If the status is `Running` this number may continue to increase + +**Result object:** + +Field | Type | Description +----------------------------------|---------|------------ +`descrLink` | string | URL of the torrent's description page +`fileName` | string | Name of the file +`fileSize` | number | Size of the file in Bytes +`fileUrl` | string | Torrent download link (usually either .torrent file or magnet link) +`nbLeechers` | number | Number of leechers +`nbSeeders` | number | Number of seeders +`siteUrl` | string | URL of the torrent site + +Example: + +```JSON +{ + "results": [ + { + "descrLink": "http://www.legittorrents.info/index.php?page=torrent-details&id=8d5f512e1acb687029b8d7cc6c5a84dce51d7a41", + "fileName": "Ubuntu-10.04-32bit-NeTV.ova", + "fileSize": -1, + "fileUrl": "http://www.legittorrents.info/download.php?id=8d5f512e1acb687029b8d7cc6c5a84dce51d7a41&f=Ubuntu-10.04-32bit-NeTV.ova.torrent", + "nbLeechers": 1, + "nbSeeders": 0, + "siteUrl": "http://www.legittorrents.info" + }, + { + "descrLink": "http://www.legittorrents.info/index.php?page=torrent-details&id=d5179f53e105dc2c2401bcfaa0c2c4936a6aa475", + "fileName": "mangOH-Legato-17_06-Ubuntu-16_04.ova", + "fileSize": -1, + "fileUrl": "http://www.legittorrents.info/download.php?id=d5179f53e105dc2c2401bcfaa0c2c4936a6aa475&f=mangOH-Legato-17_06-Ubuntu-16_04.ova.torrent", + "nbLeechers": 0, + "nbSeeders": 59, + "siteUrl": "http://www.legittorrents.info" + } + ], + "status": "Running", + "total": 2 +} +``` \ No newline at end of file diff --git a/qbittorrent-web-api-gen/src/parser/group/method/method_tests/search_result.tree b/qbittorrent-web-api-gen/src/parser/group/method/method_tests/search_result.tree new file mode 100644 index 0000000..6e9c73c --- /dev/null +++ b/qbittorrent-web-api-gen/src/parser/group/method/method_tests/search_result.tree @@ -0,0 +1,327 @@ +TokenTree { + title: None, + content: [], + children: [ + TokenTree { + title: Some( + "Get search results", + ), + content: [ + Text( + "", + ), + Text( + "Name: `results`", + ), + Text( + "", + ), + Asterisk( + "Parameters:", + ), + Text( + "", + ), + Table( + Table { + header: TableRow { + raw: "Parameter | Type | Description", + columns: [ + "Parameter", + "Type", + "Description", + ], + }, + split: "----------------------------------|---------|------------", + rows: [ + TableRow { + raw: "`id` | number | ID of the search job", + columns: [ + "id", + "number", + "ID of the search job", + ], + }, + TableRow { + raw: "`limit` _optional_ | number | max number of results to return. 0 or negative means no limit", + columns: [ + "limit _optional_", + "number", + "max number of results to return. 0 or negative means no limit", + ], + }, + TableRow { + raw: "`offset` _optional_ | number | result to start at. A negative number means count backwards (e.g. `-2` returns the 2 most recent results)", + columns: [ + "offset _optional_", + "number", + "result to start at. A negative number means count backwards (e.g. -2 returns the 2 most recent results)", + ], + }, + ], + }, + ), + Text( + "", + ), + Asterisk( + "Returns:", + ), + Text( + "", + ), + Table( + Table { + header: TableRow { + raw: "HTTP Status Code | Scenario", + columns: [ + "HTTP Status Code", + "Scenario", + ], + }, + split: "----------------------------------|---------------------", + rows: [ + TableRow { + raw: "404 | Search job was not found", + columns: [ + "404", + "Search job was not found", + ], + }, + TableRow { + raw: "409 | Offset is too large, or too small (e.g. absolute value of negative number is greater than # results)", + columns: [ + "409", + "Offset is too large, or too small (e.g. absolute value of negative number is greater than # results)", + ], + }, + TableRow { + raw: "200 | All other scenarios- see JSON below", + columns: [ + "200", + "All other scenarios- see JSON below", + ], + }, + ], + }, + ), + Text( + "", + ), + Text( + "The response is a JSON object with the following fields", + ), + Text( + "", + ), + Table( + Table { + header: TableRow { + raw: "Field | Type | Description", + columns: [ + "Field", + "Type", + "Description", + ], + }, + split: "----------------------------------|---------|------------", + rows: [ + TableRow { + raw: "`results` | array | Array of `result` objects- see table below", + columns: [ + "results", + "array", + "Array of result objects- see table below", + ], + }, + TableRow { + raw: "`status` | string | Current status of the search job (either `Running` or `Stopped`)", + columns: [ + "status", + "string", + "Current status of the search job (either Running or Stopped)", + ], + }, + TableRow { + raw: "`total` | number | Total number of results. If the status is `Running` this number may continue to increase", + columns: [ + "total", + "number", + "Total number of results. If the status is Running this number may continue to increase", + ], + }, + ], + }, + ), + Text( + "", + ), + Asterisk( + "Result object:", + ), + Text( + "", + ), + Table( + Table { + header: TableRow { + raw: "Field | Type | Description", + columns: [ + "Field", + "Type", + "Description", + ], + }, + split: "----------------------------------|---------|------------", + rows: [ + TableRow { + raw: "`descrLink` | string | URL of the torrent's description page", + columns: [ + "descrLink", + "string", + "URL of the torrent's description page", + ], + }, + TableRow { + raw: "`fileName` | string | Name of the file", + columns: [ + "fileName", + "string", + "Name of the file", + ], + }, + TableRow { + raw: "`fileSize` | number | Size of the file in Bytes", + columns: [ + "fileSize", + "number", + "Size of the file in Bytes", + ], + }, + TableRow { + raw: "`fileUrl` | string | Torrent download link (usually either .torrent file or magnet link)", + columns: [ + "fileUrl", + "string", + "Torrent download link (usually either .torrent file or magnet link)", + ], + }, + TableRow { + raw: "`nbLeechers` | number | Number of leechers", + columns: [ + "nbLeechers", + "number", + "Number of leechers", + ], + }, + TableRow { + raw: "`nbSeeders` | number | Number of seeders", + columns: [ + "nbSeeders", + "number", + "Number of seeders", + ], + }, + TableRow { + raw: "`siteUrl` | string | URL of the torrent site", + columns: [ + "siteUrl", + "string", + "URL of the torrent site", + ], + }, + ], + }, + ), + Text( + "", + ), + Text( + "Example:", + ), + Text( + "", + ), + Text( + "```JSON", + ), + Text( + "{", + ), + Text( + " \"results\": [", + ), + Text( + " {", + ), + Text( + " \"descrLink\": \"http://www.legittorrents.info/index.php?page=torrent-details&id=8d5f512e1acb687029b8d7cc6c5a84dce51d7a41\",", + ), + Text( + " \"fileName\": \"Ubuntu-10.04-32bit-NeTV.ova\",", + ), + Text( + " \"fileSize\": -1,", + ), + Text( + " \"fileUrl\": \"http://www.legittorrents.info/download.php?id=8d5f512e1acb687029b8d7cc6c5a84dce51d7a41&f=Ubuntu-10.04-32bit-NeTV.ova.torrent\",", + ), + Text( + " \"nbLeechers\": 1,", + ), + Text( + " \"nbSeeders\": 0,", + ), + Text( + " \"siteUrl\": \"http://www.legittorrents.info\"", + ), + Text( + " },", + ), + Text( + " {", + ), + Text( + " \"descrLink\": \"http://www.legittorrents.info/index.php?page=torrent-details&id=d5179f53e105dc2c2401bcfaa0c2c4936a6aa475\",", + ), + Text( + " \"fileName\": \"mangOH-Legato-17_06-Ubuntu-16_04.ova\",", + ), + Text( + " \"fileSize\": -1,", + ), + Text( + " \"fileUrl\": \"http://www.legittorrents.info/download.php?id=d5179f53e105dc2c2401bcfaa0c2c4936a6aa475&f=mangOH-Legato-17_06-Ubuntu-16_04.ova.torrent\",", + ), + Text( + " \"nbLeechers\": 0,", + ), + Text( + " \"nbSeeders\": 59,", + ), + Text( + " \"siteUrl\": \"http://www.legittorrents.info\"", + ), + Text( + " }", + ), + Text( + " ],", + ), + Text( + " \"status\": \"Running\",", + ), + Text( + " \"total\": 2", + ), + Text( + "}", + ), + Text( + "```", + ), + ], + children: [], + }, + ], +} \ No newline at end of file diff --git a/qbittorrent-web-api-gen/src/parser/group/method/mod.rs b/qbittorrent-web-api-gen/src/parser/group/method/mod.rs index a2a72b1..08d27b8 100644 --- a/qbittorrent-web-api-gen/src/parser/group/method/mod.rs +++ b/qbittorrent-web-api-gen/src/parser/group/method/mod.rs @@ -1,15 +1,15 @@ mod description; -mod parameters; mod return_type; mod url; +use std::collections::HashMap; + use crate::{md_parser, parser::util, types}; pub use return_type::ReturnType; use self::{ - description::parse_method_description, parameters::parse_parameters, - return_type::parse_return_type, url::get_method_url, + description::parse_method_description, return_type::parse_return_type, url::get_method_url, }; #[derive(Debug)] @@ -60,9 +60,10 @@ pub fn parse_api_method(child: &md_parser::TokenTree) -> Option { } fn to_api_method(child: &md_parser::TokenTree, name: &str) -> ApiMethod { + let tables = child.to_tables(); let method_description = parse_method_description(&child.content); let return_type = parse_return_type(&child.content); - let parameters = parse_parameters(&child.content).map(ApiParameters::new); + let parameters = tables.parameters().map(ApiParameters::new); let method_url = get_method_url(&child.content); ApiMethod { @@ -73,3 +74,152 @@ fn to_api_method(child: &md_parser::TokenTree, name: &str) -> ApiMethod { url: method_url, } } + +impl md_parser::TokenTree { + fn to_tables(&self) -> Tables<'_> { + let mut tables = HashMap::new(); + let mut prev_prev: Option<&md_parser::MdContent> = None; + let mut prev: Option<&md_parser::MdContent> = None; + + for content in &self.content { + if let md_parser::MdContent::Table(table) = content { + let title = match prev_prev { + Some(md_parser::MdContent::Text(text)) => text.clone(), + Some(md_parser::MdContent::Asterisk(text)) => text.clone(), + _ => panic!("Expected table title, found: {:?}", prev_prev), + }; + + tables.insert(title.replace(':', ""), table); + } + + prev_prev = prev; + prev = Some(content); + } + + Tables { tables } + } +} + +#[derive(Debug)] +struct Tables<'a> { + tables: HashMap, +} + +impl<'a> Tables<'a> { + fn parameters(&self) -> Option> { + self.get_type_containing("Parameters") + } + + // fn return_type(&self) -> Option> { + // self.get_type_containing("Returns") + // } + + fn get_type_containing(&self, name: &str) -> Option> { + self.tables + .iter() + .find(|(key, _)| key.contains(name)) + .map(|(_, table)| table.to_types()) + } +} + +impl md_parser::Table { + fn to_types(&self) -> Vec { + self.rows + .iter() + .flat_map(|table_row| table_row.to_type()) + .collect() + } +} + +impl md_parser::TableRow { + fn to_type(&self) -> Option { + let columns = &self.columns; + let type_map = HashMap::new(); + let description = columns.get(2).cloned(); + + match &columns.get(2) { + // If the description contains a default value it means that the parameter is optional. + Some(desc) if desc.contains("default: ") => { + // type defines a variable as default if it contains: _optional_ + let name_with_optional = format!("{} {}", columns[0], types::OPTIONAL); + types::Type::from(&columns[1], &name_with_optional, description, &type_map) + } + _ => types::Type::from(&columns[1], &columns[0], description, &type_map), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use md_parser::TokenTreeFactory; + + macro_rules! TEST_DIR { + () => { + "method_tests" + }; + } + + #[allow(unused_macros)] + macro_rules! run_test { + ($test_file:expr) => { + use pretty_assertions::assert_eq; + + // given + let input = include_str!(concat!(TEST_DIR!(), "/", $test_file, ".md")); + + // when + let tree = TokenTreeFactory::create(input); + let api_method = parse_api_method(&tree.children[0]).unwrap(); + + // then + let api_method_as_str = format!("{api_method:#?}"); + let should_be = include_str!(concat!(TEST_DIR!(), "/", $test_file, ".check")); + assert_eq!(api_method_as_str, should_be); + }; + } + + // use this macro when creating/updating as test + #[allow(unused_macros)] + macro_rules! update_test { + ($test_file:expr) => { + use std::fs; + use std::path::Path; + + let input = include_str!(concat!(TEST_DIR!(), "/", $test_file, ".md")); + let tree = TokenTreeFactory::create(input); + let api_method = parse_api_method(&tree.children[0]).unwrap(); + + let tree_as_str = format!("{tree:#?}"); + let api_method_as_str = format!("{api_method:#?}"); + + let tree_file = concat!( + "src/parser/group/method/", + TEST_DIR!(), + "/", + $test_file, + ".tree" + ); + let file = concat!( + "src/parser/group/method/", + TEST_DIR!(), + "/", + $test_file, + ".check" + ); + + // prevent user from accidentally leaving the current macro in a test + if Path::new(file).exists() { + panic!("Test case already exists: {file}"); + } + + fs::write(file, api_method_as_str).unwrap(); + fs::write(tree_file, tree_as_str).unwrap(); + }; + } + + #[test] + fn search_result() { + run_test!("search_result"); + } +} diff --git a/qbittorrent-web-api-gen/src/parser/group/method/parameters.rs b/qbittorrent-web-api-gen/src/parser/group/method/parameters.rs deleted file mode 100644 index 189c160..0000000 --- a/qbittorrent-web-api-gen/src/parser/group/method/parameters.rs +++ /dev/null @@ -1,51 +0,0 @@ -use std::collections::HashMap; - -use crate::{md_parser, parser::types}; - -pub fn parse_parameters(content: &[md_parser::MdContent]) -> Option> { - let mut it = content - .iter() - .skip_while(|row| match row { - md_parser::MdContent::Asterisk(content) | md_parser::MdContent::Text(content) => { - !content.starts_with("Parameters:") - } - _ => true, - }) - // Parameters: <-- skip - // <-- skip - // table with parameters <-- take - .skip(2); - - let parameter_table = match it.next() { - Some(md_parser::MdContent::Table(table)) => table, - _ => return None, - }; - - // empty for now - let type_map = HashMap::default(); - - let table = parameter_table - .rows - .iter() - .flat_map(|row| parse_parameter(row, &type_map)) - .collect(); - - Some(table) -} - -fn parse_parameter( - row: &md_parser::TableRow, - type_map: &HashMap, -) -> Option { - let description = row.columns.get(2).cloned(); - - match &row.columns.get(2) { - // If the description contains a default value it means that the parameter is optional. - Some(desc) if desc.contains("default: ") => { - // type defines a variable as default if it contains: _optional_ - let name_with_optional = format!("{} {}", row.columns[0], types::OPTIONAL); - types::Type::from(&row.columns[1], &name_with_optional, description, type_map) - } - _ => types::Type::from(&row.columns[1], &row.columns[0], description, type_map), - } -} diff --git a/qbittorrent-web-api-gen/src/types.rs b/qbittorrent-web-api-gen/src/types.rs index 5f49d9d..d56f58b 100644 --- a/qbittorrent-web-api-gen/src/types.rs +++ b/qbittorrent-web-api-gen/src/types.rs @@ -1,4 +1,3 @@ -use regex::RegexBuilder; use std::collections::HashMap; #[derive(Debug, Clone)] @@ -45,6 +44,12 @@ pub struct TypeWithRef { pub ref_type: String, } +#[derive(Debug, Clone)] +pub struct ComplexObject { + pub type_info: TypeInfo, + pub fields: Vec, +} + pub const OPTIONAL: &str = "_optional_"; #[derive(Debug, Clone)] @@ -54,8 +59,8 @@ pub enum Type { Bool(TypeInfo), String(TypeInfo), StringArray(TypeInfo), - ObjectArray(TypeWithRef), Object(TypeInfo), + // ComplexObject(ComplexObject), } impl Type { @@ -67,7 +72,7 @@ impl Type { Type::String(_) => "String".into(), Type::StringArray(_) => "String".into(), Type::Object(_) => "String".into(), - Type::ObjectArray(_) => panic!("Not implemented for ObjectArray"), + // Type::ComplexObject(_) => panic!("Not implemented for ComplexObject"), } } @@ -83,7 +88,7 @@ impl Type { Type::String(_) => "str".into(), Type::StringArray(_) => "&[str]".into(), Type::Object(_) => "str".into(), - Type::ObjectArray(_) => panic!("Not implemented for ObjectArray"), + // Type::ComplexObject(_) => panic!("Not implemented for ComplexObject"), } } @@ -99,7 +104,7 @@ impl Type { Type::String(t) => t, Type::StringArray(t) => t, Type::Object(t) => t, - Type::ObjectArray(TypeWithRef { type_info, .. }) => type_info, + // Type::ComplexObject(ComplexObject { type_info, .. }) => type_info, } } @@ -131,16 +136,17 @@ impl Type { "bool" => Some(Type::Bool(create_type_info())), "integer" | "number" | "int" => Some(Type::Number(create_type_info())), "string" => Some(Type::String(create_type_info())), - "array" => description - .clone() - .and_then(|ref desc| get_ref_type(desc)) - .map(|ref_type| { - Type::ObjectArray(TypeWithRef { - type_info: create_type_info(), - ref_type, - }) - }) - .or_else(|| Some(Type::StringArray(create_type_info()))), + "array" => Some(Type::StringArray(create_type_info())), + // "array" => description + // .clone() + // .and_then(|ref desc| get_ref_type(desc)) + // .map(|ref_type| { + // Type::ObjectArray(TypeWithRef { + // type_info: create_type_info(), + // ref_type, + // }) + // }) + // .or_else(|| Some(Type::StringArray(create_type_info()))), "object" => Some(Type::Object(create_type_info())), "float" => Some(Type::Float(create_type_info())), _ => None, @@ -148,24 +154,24 @@ impl Type { } } -fn get_ref_type(desc: &str) -> Option { - let re = RegexBuilder::new(r".*array of (\w+)\s?.*") - .case_insensitive(true) - .build() - .unwrap(); +// fn get_ref_type(desc: &str) -> Option { +// let re = RegexBuilder::new(r".*array of (\w+)\s?.*") +// .case_insensitive(true) +// .build() +// .unwrap(); - re.captures(desc) - .and_then(|captures| captures.get(1)) - .map(|m| m.as_str().to_owned()) -} +// re.captures(desc) +// .and_then(|captures| captures.get(1)) +// .map(|m| m.as_str().to_owned()) +// } #[cfg(test)] mod tests { - use super::*; + // use super::*; - #[test] - fn should_parse_object_array() { - let ref_type = get_ref_type("Array of result objects- see table below"); - assert_eq!("result", ref_type.unwrap()); - } + // #[test] + // fn should_parse_object_array() { + // let ref_type = get_ref_type("Array of result objects- see table below"); + // assert_eq!("result", ref_type.unwrap()); + // } } From 47b9701321b36bc74233144433e381bb4b72d9cb Mon Sep 17 00:00:00 2001 From: Joel Wachsler Date: Tue, 19 Jul 2022 20:36:52 +0000 Subject: [PATCH 33/47] Move methods to associated methods --- Cargo.toml | 4 +- .../src/parser/group/method/mod.rs | 60 +++++++++++-------- .../src/parser/group/mod.rs | 4 +- 3 files changed, 37 insertions(+), 31 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 70ce1b3..fdc3024 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,4 @@ serde_json = "1.0.82" thiserror = "1.0.31" [workspace] -members = [ - "qbittorrent-web-api-gen", -] +members = ["qbittorrent-web-api-gen"] diff --git a/qbittorrent-web-api-gen/src/parser/group/method/mod.rs b/qbittorrent-web-api-gen/src/parser/group/method/mod.rs index 08d27b8..fe9b399 100644 --- a/qbittorrent-web-api-gen/src/parser/group/method/mod.rs +++ b/qbittorrent-web-api-gen/src/parser/group/method/mod.rs @@ -49,39 +49,47 @@ impl ApiParameters { } } -pub fn parse_api_method(child: &md_parser::TokenTree) -> Option { - util::find_content_starts_with(&child.content, "Name: ") - .map(|name| { - name.trim_start_matches("Name: ") - .trim_matches('`') - .to_string() - }) - .map(|name| to_api_method(child, &name)) -} +impl ApiMethod { + pub fn try_new(child: &md_parser::TokenTree) -> Option { + const NAME: &str = "Name: "; -fn to_api_method(child: &md_parser::TokenTree, name: &str) -> ApiMethod { - let tables = child.to_tables(); - let method_description = parse_method_description(&child.content); - let return_type = parse_return_type(&child.content); - let parameters = tables.parameters().map(ApiParameters::new); - let method_url = get_method_url(&child.content); + child + .find_content_starts_with(NAME) + .map(|name| name.trim_start_matches(NAME).trim_matches('`').to_string()) + .map(|name| ApiMethod::new(child, &name)) + } - ApiMethod { - name: name.to_string(), - description: method_description, - parameters, - return_type, - url: method_url, + fn new(child: &md_parser::TokenTree, name: &str) -> Self { + let tables = Tables::from(child); + let method_description = parse_method_description(&child.content); + let return_type = parse_return_type(&child.content); + // let return_type = tables.return_type().map(|r| ReturnType::new(r)); + let parameters = tables.parameters().map(ApiParameters::new); + let method_url = get_method_url(&child.content); + + ApiMethod { + name: name.to_string(), + description: method_description, + parameters, + return_type, + url: method_url, + } } } impl md_parser::TokenTree { - fn to_tables(&self) -> Tables<'_> { + fn find_content_starts_with(&self, content: &str) -> Option { + util::find_content_starts_with(&self.content, content) + } +} + +impl<'a> From<&'a md_parser::TokenTree> for Tables<'a> { + fn from(token_tree: &'a md_parser::TokenTree) -> Self { let mut tables = HashMap::new(); let mut prev_prev: Option<&md_parser::MdContent> = None; let mut prev: Option<&md_parser::MdContent> = None; - for content in &self.content { + for content in &token_tree.content { if let md_parser::MdContent::Table(table) = content { let title = match prev_prev { Some(md_parser::MdContent::Text(text)) => text.clone(), @@ -111,7 +119,7 @@ impl<'a> Tables<'a> { } // fn return_type(&self) -> Option> { - // self.get_type_containing("Returns") + // self.get_type_containing("The response is a") // } fn get_type_containing(&self, name: &str) -> Option> { @@ -170,7 +178,7 @@ mod tests { // when let tree = TokenTreeFactory::create(input); - let api_method = parse_api_method(&tree.children[0]).unwrap(); + let api_method = ApiMethod::try_new(&tree.children[0]).unwrap(); // then let api_method_as_str = format!("{api_method:#?}"); @@ -187,7 +195,7 @@ mod tests { use std::path::Path; let input = include_str!(concat!(TEST_DIR!(), "/", $test_file, ".md")); - let tree = TokenTreeFactory::create(input); + let tree = ApiMethod::try_new(input); let api_method = parse_api_method(&tree.children[0]).unwrap(); let tree_as_str = format!("{tree:#?}"); diff --git a/qbittorrent-web-api-gen/src/parser/group/mod.rs b/qbittorrent-web-api-gen/src/parser/group/mod.rs index fb65ccf..b4be43d 100644 --- a/qbittorrent-web-api-gen/src/parser/group/mod.rs +++ b/qbittorrent-web-api-gen/src/parser/group/mod.rs @@ -4,7 +4,7 @@ mod url; use crate::md_parser; -use self::{description::parse_group_description, method::parse_api_method, url::get_group_url}; +use self::{description::parse_group_description, url::get_group_url}; pub use method::*; #[derive(Debug)] @@ -16,7 +16,7 @@ pub struct ApiGroup { } pub fn parse_api_group(tree: &md_parser::TokenTree) -> ApiGroup { - let methods = tree.children.iter().flat_map(parse_api_method).collect(); + let methods = tree.children.iter().flat_map(ApiMethod::try_new).collect(); let group_description = parse_group_description(&tree.content); let group_url = get_group_url(&tree.content); From bc8d014bc3b190034945126793f11760812c9402 Mon Sep 17 00:00:00 2001 From: Joel Wachsler Date: Tue, 19 Jul 2022 20:53:55 +0000 Subject: [PATCH 34/47] Move methods to TokenTree --- .../src/parser/group/description.rs | 27 ++-- .../src/parser/group/method/description.rs | 65 +++++---- .../src/parser/group/method/mod.rs | 14 +- .../src/parser/group/method/return_type.rs | 133 +++++++++--------- .../src/parser/group/method/url.rs | 12 +- .../src/parser/group/mod.rs | 45 +++--- .../src/parser/group/url.rs | 16 ++- qbittorrent-web-api-gen/src/parser/mod.rs | 7 +- 8 files changed, 162 insertions(+), 157 deletions(-) diff --git a/qbittorrent-web-api-gen/src/parser/group/description.rs b/qbittorrent-web-api-gen/src/parser/group/description.rs index c47d531..395973b 100644 --- a/qbittorrent-web-api-gen/src/parser/group/description.rs +++ b/qbittorrent-web-api-gen/src/parser/group/description.rs @@ -1,17 +1,20 @@ use crate::md_parser; -pub fn parse_group_description(content: &[md_parser::MdContent]) -> Option { - let return_desc = content - .iter() - .map(|row| row.inner_value_as_string()) - .collect::>() - .join("\n") - .trim() - .to_string(); +impl md_parser::TokenTree { + pub fn parse_group_description(&self) -> Option { + let return_desc = self + .content + .iter() + .map(|row| row.inner_value_as_string()) + .collect::>() + .join("\n") + .trim() + .to_string(); - if return_desc.is_empty() { - None - } else { - Some(return_desc) + if return_desc.is_empty() { + None + } else { + Some(return_desc) + } } } diff --git a/qbittorrent-web-api-gen/src/parser/group/method/description.rs b/qbittorrent-web-api-gen/src/parser/group/method/description.rs index dfeab4e..fb892b8 100644 --- a/qbittorrent-web-api-gen/src/parser/group/method/description.rs +++ b/qbittorrent-web-api-gen/src/parser/group/method/description.rs @@ -1,35 +1,38 @@ -use crate::md_parser::MdContent; +use crate::md_parser::{self, MdContent}; -pub fn parse_method_description(content: &[MdContent]) -> Option { - let return_desc = content - .iter() - // skip until we get to the "Returns:" text - .skip_while(|row| match row { - MdContent::Asterisk(text) => !text.starts_with("Returns:"), - _ => true, - }) - // there is one space before the table - .skip(2) - .skip_while(|row| match row { - MdContent::Text(text) => !text.is_empty(), - _ => true, - }) - // and there is one space after the table - .skip(1) - // then what is left should be the description - .flat_map(|row| match row { - MdContent::Text(text) => Some(text), - _ => None, - }) - .cloned() - .collect::>() - .join("\n") - .trim() - .to_string(); +impl md_parser::TokenTree { + pub fn parse_method_description(&self) -> Option { + let return_desc = self + .content + .iter() + // skip until we get to the "Returns:" text + .skip_while(|row| match row { + MdContent::Asterisk(text) => !text.starts_with("Returns:"), + _ => true, + }) + // there is one space before the table + .skip(2) + .skip_while(|row| match row { + MdContent::Text(text) => !text.is_empty(), + _ => true, + }) + // and there is one space after the table + .skip(1) + // then what is left should be the description + .flat_map(|row| match row { + MdContent::Text(text) => Some(text), + _ => None, + }) + .cloned() + .collect::>() + .join("\n") + .trim() + .to_string(); - if return_desc.is_empty() { - None - } else { - Some(return_desc) + if return_desc.is_empty() { + None + } else { + Some(return_desc) + } } } diff --git a/qbittorrent-web-api-gen/src/parser/group/method/mod.rs b/qbittorrent-web-api-gen/src/parser/group/method/mod.rs index fe9b399..b920f10 100644 --- a/qbittorrent-web-api-gen/src/parser/group/method/mod.rs +++ b/qbittorrent-web-api-gen/src/parser/group/method/mod.rs @@ -2,15 +2,9 @@ mod description; mod return_type; mod url; -use std::collections::HashMap; - use crate::{md_parser, parser::util, types}; - pub use return_type::ReturnType; - -use self::{ - description::parse_method_description, return_type::parse_return_type, url::get_method_url, -}; +use std::collections::HashMap; #[derive(Debug)] pub struct ApiMethod { @@ -61,11 +55,11 @@ impl ApiMethod { fn new(child: &md_parser::TokenTree, name: &str) -> Self { let tables = Tables::from(child); - let method_description = parse_method_description(&child.content); - let return_type = parse_return_type(&child.content); + let method_description = child.parse_method_description(); + let return_type = child.parse_return_type(); // let return_type = tables.return_type().map(|r| ReturnType::new(r)); let parameters = tables.parameters().map(ApiParameters::new); - let method_url = get_method_url(&child.content); + let method_url = child.get_method_url(); ApiMethod { name: name.to_string(), diff --git a/qbittorrent-web-api-gen/src/parser/group/method/return_type.rs b/qbittorrent-web-api-gen/src/parser/group/method/return_type.rs index 6ff8342..3691c1f 100644 --- a/qbittorrent-web-api-gen/src/parser/group/method/return_type.rs +++ b/qbittorrent-web-api-gen/src/parser/group/method/return_type.rs @@ -11,81 +11,84 @@ pub struct ReturnType { pub parameters: Vec, } -pub fn parse_return_type(content: &[MdContent]) -> Option { - let table = content - .iter() - // The response is a ... <-- Trying to find this line - // <-- The next line is empty - // Table with the return type <-- And then extract the following type table - .skip_while(|row| match row { - MdContent::Text(text) => !text.starts_with("The response is a"), - _ => true, +impl md_parser::TokenTree { + pub fn parse_return_type(&self) -> Option { + let table = self + .content + .iter() + // The response is a ... <-- Trying to find this line + // <-- The next line is empty + // Table with the return type <-- And then extract the following type table + .skip_while(|row| match row { + MdContent::Text(text) => !text.starts_with("The response is a"), + _ => true, + }) + .find_map(|row| match row { + MdContent::Table(table) => Some(table), + _ => None, + })?; + + let types = self.parse_object_types(); + + let parameters = table + .rows + .iter() + .map(|parameter| ReturnTypeParameter { + name: parameter.columns[0].clone(), + description: parameter.columns[2].clone(), + return_type: types::Type::from( + ¶meter.columns[1], + ¶meter.columns[0], + Some(parameter.columns[2].clone()), + &types, + ) + .unwrap_or_else(|| panic!("Failed to parse type {}", ¶meter.columns[1])), + }) + .collect(); + + Some(ReturnType { + parameters, + is_list: self.is_list(), }) - .find_map(|row| match row { - MdContent::Table(table) => Some(table), - _ => None, - })?; + } - let types = parse_object_types(content); + fn is_list(&self) -> bool { + self.content + .iter() + .find_map(|row| match row { + MdContent::Text(text) if text.starts_with("The response is a") => Some(text), + _ => None, + }) + .map(|found| found.contains("array")) + .unwrap_or_else(|| false) + } - let parameters = table - .rows - .iter() - .map(|parameter| ReturnTypeParameter { - name: parameter.columns[0].clone(), - description: parameter.columns[2].clone(), - return_type: types::Type::from( - ¶meter.columns[1], - ¶meter.columns[0], - Some(parameter.columns[2].clone()), - &types, - ) - .unwrap_or_else(|| panic!("Failed to parse type {}", ¶meter.columns[1])), - }) - .collect(); + pub fn parse_object_types(&self) -> HashMap { + let mut output = HashMap::new(); + let mut content_it = self.content.iter(); - let is_list = content - .iter() - .find_map(|row| match row { - MdContent::Text(text) if text.starts_with("The response is a") => Some(text), - _ => None, - }) - .map(|found| found.contains("array")) - .unwrap_or_else(|| false); + while let Some(entry) = content_it.next() { + if let md_parser::MdContent::Text(content) = entry { + const POSSIBLE_VALUES_OF: &str = "Possible values of "; + if content.contains(POSSIBLE_VALUES_OF) { + // is empty + content_it.next(); + if let Some(md_parser::MdContent::Table(table)) = content_it.next() { + let enum_types = to_type_descriptions(table); - Some(ReturnType { - parameters, - is_list, - }) -} + let name = content + .trim_start_matches(POSSIBLE_VALUES_OF) + .replace('`', "") + .replace(':', ""); -pub fn parse_object_types( - content: &[md_parser::MdContent], -) -> HashMap { - let mut output = HashMap::new(); - let mut content_it = content.iter(); - - while let Some(entry) = content_it.next() { - if let md_parser::MdContent::Text(content) = entry { - const POSSIBLE_VALUES_OF: &str = "Possible values of "; - if content.contains(POSSIBLE_VALUES_OF) { - // is empty - content_it.next(); - if let Some(md_parser::MdContent::Table(table)) = content_it.next() { - let enum_types = to_type_descriptions(table); - - let name = content - .trim_start_matches(POSSIBLE_VALUES_OF) - .replace('`', "") - .replace(':', ""); - - output.insert(name, types::TypeDescription { values: enum_types }); + output.insert(name, types::TypeDescription { values: enum_types }); + } } } } - } - output + output + } } fn to_type_descriptions(table: &md_parser::Table) -> Vec { diff --git a/qbittorrent-web-api-gen/src/parser/group/method/url.rs b/qbittorrent-web-api-gen/src/parser/group/method/url.rs index 5358362..1911961 100644 --- a/qbittorrent-web-api-gen/src/parser/group/method/url.rs +++ b/qbittorrent-web-api-gen/src/parser/group/method/url.rs @@ -1,9 +1,11 @@ use crate::{md_parser, parser::util}; -pub fn get_method_url(content: &[md_parser::MdContent]) -> String { - const START: &str = "Name: "; +impl md_parser::TokenTree { + pub fn get_method_url(&self) -> String { + const START: &str = "Name: "; - util::find_content_starts_with(content, START) - .map(|text| text.trim_start_matches(START).trim_matches('`').to_string()) - .expect("Could find method url") + util::find_content_starts_with(&self.content, START) + .map(|text| text.trim_start_matches(START).trim_matches('`').to_string()) + .expect("Could find method url") + } } diff --git a/qbittorrent-web-api-gen/src/parser/group/mod.rs b/qbittorrent-web-api-gen/src/parser/group/mod.rs index b4be43d..df6730d 100644 --- a/qbittorrent-web-api-gen/src/parser/group/mod.rs +++ b/qbittorrent-web-api-gen/src/parser/group/mod.rs @@ -4,7 +4,6 @@ mod url; use crate::md_parser; -use self::{description::parse_group_description, url::get_group_url}; pub use method::*; #[derive(Debug)] @@ -15,25 +14,29 @@ pub struct ApiGroup { pub url: String, } -pub fn parse_api_group(tree: &md_parser::TokenTree) -> ApiGroup { - let methods = tree.children.iter().flat_map(ApiMethod::try_new).collect(); - - let group_description = parse_group_description(&tree.content); - let group_url = get_group_url(&tree.content); - - let name = tree - .title - .clone() - .unwrap() - .to_lowercase() - .trim_end_matches("(experimental)") - .trim() - .replace(' ', "_"); - - ApiGroup { - name, - methods, - description: group_description, - url: group_url, +impl ApiGroup { + pub fn new(tree: &md_parser::TokenTree) -> ApiGroup { + ApiGroup { + name: tree.name(), + methods: tree.methods(), + description: tree.parse_group_description(), + url: tree.get_group_url(), + } + } +} + +impl md_parser::TokenTree { + fn name(&self) -> String { + self.title + .clone() + .unwrap() + .to_lowercase() + .trim_end_matches("(experimental)") + .trim() + .replace(' ', "_") + } + + fn methods(&self) -> Vec { + self.children.iter().flat_map(ApiMethod::try_new).collect() } } diff --git a/qbittorrent-web-api-gen/src/parser/group/url.rs b/qbittorrent-web-api-gen/src/parser/group/url.rs index 993c9b8..b806b8c 100644 --- a/qbittorrent-web-api-gen/src/parser/group/url.rs +++ b/qbittorrent-web-api-gen/src/parser/group/url.rs @@ -2,13 +2,15 @@ use regex::Regex; use crate::{md_parser, parser::util}; -pub fn get_group_url(content: &[md_parser::MdContent]) -> String { - let row = util::find_content_contains(content, "API methods are under") - .expect("Could not find api method"); +impl md_parser::TokenTree { + pub fn get_group_url(&self) -> String { + let row = util::find_content_contains(&self.content, "API methods are under") + .expect("Could not find api method"); - let re = Regex::new(r#"All (?:\w+\s?)+ API methods are under "(\w+)", e.g."#) - .expect("Failed to create regex"); + let re = Regex::new(r#"All (?:\w+\s?)+ API methods are under "(\w+)", e.g."#) + .expect("Failed to create regex"); - let res = re.captures(&row).expect("Failed find capture"); - res[1].to_string() + let res = re.captures(&row).expect("Failed find capture"); + res[1].to_string() + } } diff --git a/qbittorrent-web-api-gen/src/parser/mod.rs b/qbittorrent-web-api-gen/src/parser/mod.rs index 414d179..ec3b78a 100644 --- a/qbittorrent-web-api-gen/src/parser/mod.rs +++ b/qbittorrent-web-api-gen/src/parser/mod.rs @@ -1,7 +1,5 @@ use crate::{md_parser, types}; -use self::group::parse_api_group; - mod group; mod util; @@ -19,10 +17,7 @@ pub fn parse_api_groups(token_tree: md_parser::TokenTree) -> Vec { } pub fn parse_groups(trees: Vec) -> Vec { - trees - .into_iter() - .map(|tree| parse_api_group(&tree)) - .collect() + trees.iter().map(ApiGroup::new).collect() } fn extract_relevant_parts(tree: md_parser::TokenTree) -> Vec { From f430e82b7a6cf9570a874ea2a136a99a96518796 Mon Sep 17 00:00:00 2001 From: Joel Wachsler Date: Tue, 19 Jul 2022 21:04:18 +0000 Subject: [PATCH 35/47] Move more functionality --- .../src/parser/group/method/return_type.rs | 62 ++++++++++++------- 1 file changed, 39 insertions(+), 23 deletions(-) diff --git a/qbittorrent-web-api-gen/src/parser/group/method/return_type.rs b/qbittorrent-web-api-gen/src/parser/group/method/return_type.rs index 3691c1f..0dccc17 100644 --- a/qbittorrent-web-api-gen/src/parser/group/method/return_type.rs +++ b/qbittorrent-web-api-gen/src/parser/group/method/return_type.rs @@ -33,17 +33,7 @@ impl md_parser::TokenTree { let parameters = table .rows .iter() - .map(|parameter| ReturnTypeParameter { - name: parameter.columns[0].clone(), - description: parameter.columns[2].clone(), - return_type: types::Type::from( - ¶meter.columns[1], - ¶meter.columns[0], - Some(parameter.columns[2].clone()), - &types, - ) - .unwrap_or_else(|| panic!("Failed to parse type {}", ¶meter.columns[1])), - }) + .map(|parameter| parameter.to_return_type_parameter(&types)) .collect(); Some(ReturnType { @@ -74,14 +64,12 @@ impl md_parser::TokenTree { // is empty content_it.next(); if let Some(md_parser::MdContent::Table(table)) = content_it.next() { - let enum_types = to_type_descriptions(table); - let name = content .trim_start_matches(POSSIBLE_VALUES_OF) .replace('`', "") .replace(':', ""); - output.insert(name, types::TypeDescription { values: enum_types }); + output.insert(name, table.to_type_description()); } } } @@ -91,13 +79,41 @@ impl md_parser::TokenTree { } } -fn to_type_descriptions(table: &md_parser::Table) -> Vec { - table - .rows - .iter() - .map(|row| types::TypeDescriptions { - value: row.columns[0].to_string(), - description: row.columns[1].to_string(), - }) - .collect() +impl md_parser::Table { + pub fn to_type_description(&self) -> types::TypeDescription { + types::TypeDescription { + values: self.to_type_descriptions(), + } + } + + pub fn to_type_descriptions(&self) -> Vec { + self.rows + .iter() + .map(|row| types::TypeDescriptions { + value: row.columns[0].to_string(), + description: row.columns[1].to_string(), + }) + .collect() + } +} + +impl md_parser::TableRow { + fn to_return_type_parameter( + &self, + types: &HashMap, + ) -> ReturnTypeParameter { + let columns = &self.columns; + + ReturnTypeParameter { + name: columns[0].clone(), + description: columns[2].clone(), + return_type: types::Type::from( + &columns[1], + &columns[0], + Some(columns[2].clone()), + types, + ) + .unwrap_or_else(|| panic!("Failed to parse type {}", &columns[1])), + } + } } From af49a830346955c2bdcf2b48a6899f44b9f6c418 Mon Sep 17 00:00:00 2001 From: Joel Wachsler Date: Tue, 19 Jul 2022 22:10:43 +0000 Subject: [PATCH 36/47] Simplify return type parsing --- .../src/parser/group/method/mod.rs | 37 ++++++--- .../src/parser/group/method/return_type.rs | 77 +++++++++---------- 2 files changed, 62 insertions(+), 52 deletions(-) diff --git a/qbittorrent-web-api-gen/src/parser/group/method/mod.rs b/qbittorrent-web-api-gen/src/parser/group/method/mod.rs index b920f10..e3de6cf 100644 --- a/qbittorrent-web-api-gen/src/parser/group/method/mod.rs +++ b/qbittorrent-web-api-gen/src/parser/group/method/mod.rs @@ -58,7 +58,9 @@ impl ApiMethod { let method_description = child.parse_method_description(); let return_type = child.parse_return_type(); // let return_type = tables.return_type().map(|r| ReturnType::new(r)); - let parameters = tables.parameters().map(ApiParameters::new); + let parameters = tables + .get_type_containing("Parameters") + .map(ApiParameters::new); let method_url = child.get_method_url(); ApiMethod { @@ -108,19 +110,24 @@ struct Tables<'a> { } impl<'a> Tables<'a> { - fn parameters(&self) -> Option> { - self.get_type_containing("Parameters") + fn get_type_containing(&self, name: &str) -> Option> { + self.get_type_containing_as_table(name) + .map(|table| table.to_types()) } - // fn return_type(&self) -> Option> { - // self.get_type_containing("The response is a") - // } + fn get_type_containing_as_table(&self, name: &str) -> Option<&md_parser::Table> { + self.get_all_type_containing_as_table(name) + .iter() + .map(|(_, table)| *table) + .find(|_| true) + } - fn get_type_containing(&self, name: &str) -> Option> { + fn get_all_type_containing_as_table(&self, name: &str) -> HashMap { self.tables .iter() - .find(|(key, _)| key.contains(name)) - .map(|(_, table)| table.to_types()) + .filter(|(key, _)| key.contains(name)) + .map(|(k, table)| (k.clone(), *table)) + .collect() } } @@ -135,8 +142,14 @@ impl md_parser::Table { impl md_parser::TableRow { fn to_type(&self) -> Option { + self.to_types_with_types(&HashMap::new()) + } + + fn to_types_with_types( + &self, + type_map: &HashMap, + ) -> Option { let columns = &self.columns; - let type_map = HashMap::new(); let description = columns.get(2).cloned(); match &columns.get(2) { @@ -144,9 +157,9 @@ impl md_parser::TableRow { Some(desc) if desc.contains("default: ") => { // type defines a variable as default if it contains: _optional_ let name_with_optional = format!("{} {}", columns[0], types::OPTIONAL); - types::Type::from(&columns[1], &name_with_optional, description, &type_map) + types::Type::from(&columns[1], &name_with_optional, description, type_map) } - _ => types::Type::from(&columns[1], &columns[0], description, &type_map), + _ => types::Type::from(&columns[1], &columns[0], description, type_map), } } } diff --git a/qbittorrent-web-api-gen/src/parser/group/method/return_type.rs b/qbittorrent-web-api-gen/src/parser/group/method/return_type.rs index 0dccc17..72fa7fc 100644 --- a/qbittorrent-web-api-gen/src/parser/group/method/return_type.rs +++ b/qbittorrent-web-api-gen/src/parser/group/method/return_type.rs @@ -5,39 +5,43 @@ use crate::{ parser::{types, ReturnTypeParameter}, }; +use super::Tables; + #[derive(Debug)] pub struct ReturnType { pub is_list: bool, pub parameters: Vec, } +impl md_parser::Table { + fn to_return_type_parameters( + &self, + types: &HashMap, + ) -> Vec { + self.rows + .iter() + .map(|parameter| parameter.to_return_type_parameter(types)) + .collect() + } +} + impl md_parser::TokenTree { pub fn parse_return_type(&self) -> Option { - let table = self - .content - .iter() - // The response is a ... <-- Trying to find this line - // <-- The next line is empty - // Table with the return type <-- And then extract the following type table - .skip_while(|row| match row { - MdContent::Text(text) => !text.starts_with("The response is a"), - _ => true, - }) - .find_map(|row| match row { - MdContent::Table(table) => Some(table), - _ => None, + let tables: Tables = self.into(); + let table = tables + .get_type_containing_as_table("The response is a") + // these two are special cases not following a pattern + .or_else(|| tables.get_type_containing_as_table("Possible fields")) + .or_else(|| { + tables.get_type_containing_as_table( + "Each element of the array has the following properties", + ) })?; let types = self.parse_object_types(); - let parameters = table - .rows - .iter() - .map(|parameter| parameter.to_return_type_parameter(&types)) - .collect(); - Some(ReturnType { - parameters, + parameters: table.to_return_type_parameters(&types), is_list: self.is_list(), }) } @@ -54,28 +58,21 @@ impl md_parser::TokenTree { } pub fn parse_object_types(&self) -> HashMap { - let mut output = HashMap::new(); - let mut content_it = self.content.iter(); + let tables: Tables = self.into(); + const POSSIBLE_VALUES_OF: &str = "Possible values of "; - while let Some(entry) = content_it.next() { - if let md_parser::MdContent::Text(content) = entry { - const POSSIBLE_VALUES_OF: &str = "Possible values of "; - if content.contains(POSSIBLE_VALUES_OF) { - // is empty - content_it.next(); - if let Some(md_parser::MdContent::Table(table)) = content_it.next() { - let name = content - .trim_start_matches(POSSIBLE_VALUES_OF) - .replace('`', "") - .replace(':', ""); + tables + .get_all_type_containing_as_table(POSSIBLE_VALUES_OF) + .iter() + .map(|(k, table)| { + let name = k + .trim_start_matches(POSSIBLE_VALUES_OF) + .replace('`', "") + .replace(':', ""); - output.insert(name, table.to_type_description()); - } - } - } - } - - output + (name, table.to_type_description()) + }) + .collect() } } From 135f4861ffc413865b4bee6b721ccf0917958130 Mon Sep 17 00:00:00 2001 From: Joel Wachsler Date: Tue, 19 Jul 2022 22:24:02 +0000 Subject: [PATCH 37/47] Remove util --- .../src/parser/group/method/mod.rs | 11 ++++++++--- .../src/parser/group/method/return_type.rs | 9 ++------- .../src/parser/group/method/url.rs | 4 ++-- qbittorrent-web-api-gen/src/parser/group/url.rs | 14 ++++++++++++-- qbittorrent-web-api-gen/src/parser/mod.rs | 1 - qbittorrent-web-api-gen/src/parser/util.rs | 15 --------------- 6 files changed, 24 insertions(+), 30 deletions(-) delete mode 100644 qbittorrent-web-api-gen/src/parser/util.rs diff --git a/qbittorrent-web-api-gen/src/parser/group/method/mod.rs b/qbittorrent-web-api-gen/src/parser/group/method/mod.rs index e3de6cf..1099227 100644 --- a/qbittorrent-web-api-gen/src/parser/group/method/mod.rs +++ b/qbittorrent-web-api-gen/src/parser/group/method/mod.rs @@ -2,7 +2,7 @@ mod description; mod return_type; mod url; -use crate::{md_parser, parser::util, types}; +use crate::{md_parser, types}; pub use return_type::ReturnType; use std::collections::HashMap; @@ -74,8 +74,13 @@ impl ApiMethod { } impl md_parser::TokenTree { - fn find_content_starts_with(&self, content: &str) -> Option { - util::find_content_starts_with(&self.content, content) + fn find_content_starts_with(&self, starts_with: &str) -> Option { + self.content.iter().find_map(|row| match row { + md_parser::MdContent::Text(content) if content.starts_with(starts_with) => { + Some(content.into()) + } + _ => None, + }) } } diff --git a/qbittorrent-web-api-gen/src/parser/group/method/return_type.rs b/qbittorrent-web-api-gen/src/parser/group/method/return_type.rs index 72fa7fc..6b8fc5b 100644 --- a/qbittorrent-web-api-gen/src/parser/group/method/return_type.rs +++ b/qbittorrent-web-api-gen/src/parser/group/method/return_type.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use crate::{ - md_parser::{self, MdContent}, + md_parser, parser::{types, ReturnTypeParameter}, }; @@ -47,12 +47,7 @@ impl md_parser::TokenTree { } fn is_list(&self) -> bool { - self.content - .iter() - .find_map(|row| match row { - MdContent::Text(text) if text.starts_with("The response is a") => Some(text), - _ => None, - }) + self.find_content_starts_with("The response is a") .map(|found| found.contains("array")) .unwrap_or_else(|| false) } diff --git a/qbittorrent-web-api-gen/src/parser/group/method/url.rs b/qbittorrent-web-api-gen/src/parser/group/method/url.rs index 1911961..ff35a32 100644 --- a/qbittorrent-web-api-gen/src/parser/group/method/url.rs +++ b/qbittorrent-web-api-gen/src/parser/group/method/url.rs @@ -1,10 +1,10 @@ -use crate::{md_parser, parser::util}; +use crate::md_parser; impl md_parser::TokenTree { pub fn get_method_url(&self) -> String { const START: &str = "Name: "; - util::find_content_starts_with(&self.content, START) + self.find_content_starts_with(START) .map(|text| text.trim_start_matches(START).trim_matches('`').to_string()) .expect("Could find method url") } diff --git a/qbittorrent-web-api-gen/src/parser/group/url.rs b/qbittorrent-web-api-gen/src/parser/group/url.rs index b806b8c..4f67c6f 100644 --- a/qbittorrent-web-api-gen/src/parser/group/url.rs +++ b/qbittorrent-web-api-gen/src/parser/group/url.rs @@ -1,10 +1,11 @@ use regex::Regex; -use crate::{md_parser, parser::util}; +use crate::md_parser; impl md_parser::TokenTree { pub fn get_group_url(&self) -> String { - let row = util::find_content_contains(&self.content, "API methods are under") + let row = self + .find_content_contains("API methods are under") .expect("Could not find api method"); let re = Regex::new(r#"All (?:\w+\s?)+ API methods are under "(\w+)", e.g."#) @@ -13,4 +14,13 @@ impl md_parser::TokenTree { let res = re.captures(&row).expect("Failed find capture"); res[1].to_string() } + + fn find_content_contains(&self, contains: &str) -> Option { + self.content.iter().find_map(|row| match row { + md_parser::MdContent::Text(content) if content.contains(contains) => { + Some(content.into()) + } + _ => None, + }) + } } diff --git a/qbittorrent-web-api-gen/src/parser/mod.rs b/qbittorrent-web-api-gen/src/parser/mod.rs index ec3b78a..e5d8968 100644 --- a/qbittorrent-web-api-gen/src/parser/mod.rs +++ b/qbittorrent-web-api-gen/src/parser/mod.rs @@ -1,7 +1,6 @@ use crate::{md_parser, types}; mod group; -mod util; #[derive(Debug)] pub struct ReturnTypeParameter { diff --git a/qbittorrent-web-api-gen/src/parser/util.rs b/qbittorrent-web-api-gen/src/parser/util.rs deleted file mode 100644 index 71e9160..0000000 --- a/qbittorrent-web-api-gen/src/parser/util.rs +++ /dev/null @@ -1,15 +0,0 @@ -use crate::md_parser::MdContent; - -pub fn find_content_starts_with(content: &[MdContent], starts_with: &str) -> Option { - content.iter().find_map(|row| match row { - MdContent::Text(content) if content.starts_with(starts_with) => Some(content.into()), - _ => None, - }) -} - -pub fn find_content_contains(content: &[MdContent], contains: &str) -> Option { - content.iter().find_map(|row| match row { - MdContent::Text(content) if content.contains(contains) => Some(content.into()), - _ => None, - }) -} From a93e8e7a02390e082456ecd66bdaa8bf834246a5 Mon Sep 17 00:00:00 2001 From: Joel Wachsler Date: Tue, 19 Jul 2022 22:41:35 +0000 Subject: [PATCH 38/47] Re-use to types --- .../src/parser/group/method/return_type.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/qbittorrent-web-api-gen/src/parser/group/method/return_type.rs b/qbittorrent-web-api-gen/src/parser/group/method/return_type.rs index 6b8fc5b..f7a4c45 100644 --- a/qbittorrent-web-api-gen/src/parser/group/method/return_type.rs +++ b/qbittorrent-web-api-gen/src/parser/group/method/return_type.rs @@ -92,20 +92,16 @@ impl md_parser::Table { impl md_parser::TableRow { fn to_return_type_parameter( &self, - types: &HashMap, + type_map: &HashMap, ) -> ReturnTypeParameter { let columns = &self.columns; ReturnTypeParameter { name: columns[0].clone(), description: columns[2].clone(), - return_type: types::Type::from( - &columns[1], - &columns[0], - Some(columns[2].clone()), - types, - ) - .unwrap_or_else(|| panic!("Failed to parse type {}", &columns[1])), + return_type: self + .to_types_with_types(type_map) + .unwrap_or_else(|| panic!("Failed to parse type {}", &columns[1])), } } } From 68bb159dc3c1d545ace7588fae7545a577589278 Mon Sep 17 00:00:00 2001 From: Joel Wachsler Date: Fri, 22 Jul 2022 14:29:01 +0000 Subject: [PATCH 39/47] Progress --- qbittorrent-web-api-gen/groups.txt | 8969 +++++++---------- .../src/generate/group/mod.rs | 427 +- .../src/generate/skeleton.rs | 12 +- .../group/method/method_tests/enum.check | 37 + .../parser/group/method/method_tests/enum.md | 12 + .../group/method/method_tests/enum.tree | 67 + .../method/method_tests/search_result.check | 262 +- .../src/parser/group/method/mod.rs | 264 +- qbittorrent-web-api-gen/src/types.rs | 92 +- qbittorrent-web-api-gen/tests/search_types.rs | 7 +- 10 files changed, 4391 insertions(+), 5758 deletions(-) create mode 100644 qbittorrent-web-api-gen/src/parser/group/method/method_tests/enum.check create mode 100644 qbittorrent-web-api-gen/src/parser/group/method/method_tests/enum.md create mode 100644 qbittorrent-web-api-gen/src/parser/group/method/method_tests/enum.tree diff --git a/qbittorrent-web-api-gen/groups.txt b/qbittorrent-web-api-gen/groups.txt index c32ae2f..4984ab4 100644 --- a/qbittorrent-web-api-gen/groups.txt +++ b/qbittorrent-web-api-gen/groups.txt @@ -7,44 +7,47 @@ description: Some( "Upon success, the response will contain a cookie with your SID. You must supply the cookie whenever you want to perform an operation that requires authentication.\n\nExample showing how to login and execute a command that requires authentication using `curl`:\n\n```sh\n$ curl -i --header 'Referer: http://localhost:8080' --data 'username=admin&password=adminadmin' http://localhost:8080/api/v2/auth/login\nHTTP/1.1 200 OK\nContent-Encoding:\nContent-Length: 3\nContent-Type: text/plain; charset=UTF-8\nSet-Cookie: SID=hBc7TxF76ERhvIw0jQQ4LZ7Z1jQUV0tQ; path=/\n$ curl http://localhost:8080/api/v2/torrents/info --cookie \"SID=hBc7TxF76ERhvIw0jQQ4LZ7Z1jQUV0tQ\"\n```\n\nNote: Set `Referer` or `Origin` header to the exact same domain and port as used in the HTTP query `Host` header.", ), - parameters: Some( - ApiParameters { - mandatory: [ - String( - TypeInfo { - name: "username", - is_optional: false, - is_list: false, - description: Some( - "Username used to access the WebUI", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "password", - is_optional: false, - is_list: false, - description: Some( - "Password used to access the WebUI", - ), - type_description: None, - }, - ), - ], - optional: [], - }, - ), - return_type: None, url: "login", + types: CompositeTypes { + composite_types: [ + Parameters( + TypeWithoutName { + types: [ + String( + TypeInfo { + name: "username", + is_optional: false, + is_list: false, + description: Some( + "Username used to access the WebUI", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "password", + is_optional: false, + is_list: false, + description: Some( + "Password used to access the WebUI", + ), + type_description: None, + }, + ), + ], + }, + ), + ], + }, }, ApiMethod { name: "logout", description: None, - parameters: None, - return_type: None, url: "logout", + types: CompositeTypes { + composite_types: [], + }, }, ], description: Some( @@ -60,2532 +63,453 @@ description: Some( "The response is a string with the application version, e.g. `v4.1.3`", ), - parameters: None, - return_type: None, url: "version", + types: CompositeTypes { + composite_types: [], + }, }, ApiMethod { name: "webapiVersion", description: Some( "The response is a string with the WebAPI version, e.g. `2.0`", ), - parameters: None, - return_type: None, url: "webapiVersion", + types: CompositeTypes { + composite_types: [], + }, }, ApiMethod { name: "buildInfo", description: Some( "The response is a JSON object containing the following fields", ), - parameters: None, - return_type: Some( - ReturnType { - is_list: false, - parameters: [ - ReturnTypeParameter { - name: "qt", - description: "QT version", - return_type: String( - TypeInfo { - name: "qt", - is_optional: false, - is_list: false, - description: Some( - "QT version", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "libtorrent", - description: "libtorrent version", - return_type: String( - TypeInfo { - name: "libtorrent", - is_optional: false, - is_list: false, - description: Some( - "libtorrent version", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "boost", - description: "Boost version", - return_type: String( - TypeInfo { - name: "boost", - is_optional: false, - is_list: false, - description: Some( - "Boost version", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "openssl", - description: "OpenSSL version", - return_type: String( - TypeInfo { - name: "openssl", - is_optional: false, - is_list: false, - description: Some( - "OpenSSL version", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "bitness", - description: "Application bitness (e.g. 64-bit)", - return_type: Number( - TypeInfo { - name: "bitness", - is_optional: false, - is_list: false, - description: Some( - "Application bitness (e.g. 64-bit)", - ), - type_description: None, - }, - ), - }, - ], - }, - ), url: "buildInfo", + types: CompositeTypes { + composite_types: [ + Response( + TypeWithoutName { + types: [ + String( + TypeInfo { + name: "qt", + is_optional: false, + is_list: false, + description: Some( + "QT version", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "libtorrent", + is_optional: false, + is_list: false, + description: Some( + "libtorrent version", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "boost", + is_optional: false, + is_list: false, + description: Some( + "Boost version", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "openssl", + is_optional: false, + is_list: false, + description: Some( + "OpenSSL version", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "bitness", + is_optional: false, + is_list: false, + description: Some( + "Application bitness (e.g. 64-bit)", + ), + type_description: None, + }, + ), + ], + }, + ), + ], + }, }, ApiMethod { name: "shutdown", description: None, - parameters: None, - return_type: None, url: "shutdown", + types: CompositeTypes { + composite_types: [], + }, }, ApiMethod { name: "preferences", description: Some( "The response is a JSON object with several fields (key-value) pairs representing the application's settings. The contents may vary depending on which settings are present in qBittorrent.ini.\n\nPossible fields:\n\n\nPossible values of `scan_dirs`:\n\n\nPossible values of `scheduler_days`:\n\n\nPossible values of `encryption`:\n\n\nNB: the first options allows you to use both encrypted and unencrypted connections (this is the default); other options are mutually exclusive: e.g. by forcing encryption on you won't be able to use unencrypted connections and vice versa.\n\nPossible values of `proxy_type`:\n\n\nPossible values of `dyndns_service`:\n\n\nPossible values of `max_ratio_act`:\n\n\nPossible values of `bittorrent_protocol`:\n\n\nPossible values of `upload_choking_algorithm`:\n\n\nPossible values of `upload_slots_behavior`:\n\n\nPossible values of `utp_tcp_mixed_mode`:\n\n\nExample:\n\n```JSON\n{\n \"add_trackers\": \"\",\n \"add_trackers_enabled\": false,\n \"alt_dl_limit\": 10240,\n \"alt_up_limit\": 10240,\n \"alternative_webui_enabled\": false,\n \"alternative_webui_path\": \"/home/user/Documents/qbit-webui\",\n \"announce_ip\": \"\",\n \"announce_to_all_tiers\": true,\n \"announce_to_all_trackers\": false,\n \"anonymous_mode\": false,\n \"async_io_threads\": 4,\n \"auto_delete_mode\": 0,\n \"auto_tmm_enabled\": false,\n \"autorun_enabled\": false,\n \"autorun_program\": \"\",\n \"banned_IPs\": \"\",\n \"bittorrent_protocol\": 0,\n \"bypass_auth_subnet_whitelist\": \"\",\n \"bypass_auth_subnet_whitelist_enabled\": false,\n \"bypass_local_auth\": false,\n \"category_changed_tmm_enabled\": false,\n \"checking_memory_use\": 32,\n \"create_subfolder_enabled\": true,\n \"current_interface_address\": \"\",\n \"current_network_interface\": \"\",\n \"dht\": true,\n \"disk_cache\": -1,\n \"disk_cache_ttl\": 60,\n \"dl_limit\": 0,\n \"dont_count_slow_torrents\": false,\n \"dyndns_domain\": \"changeme.dyndns.org\",\n \"dyndns_enabled\": false,\n \"dyndns_password\": \"\",\n \"dyndns_service\": 0,\n \"dyndns_username\": \"\",\n \"embedded_tracker_port\": 9000,\n \"enable_coalesce_read_write\": false,\n \"enable_embedded_tracker\": false,\n \"enable_multi_connections_from_same_ip\": false,\n \"enable_os_cache\": true,\n \"enable_piece_extent_affinity\": false,\n \"enable_upload_suggestions\": false,\n \"encryption\": 0,\n \"export_dir\": \"/home/user/Downloads/all\",\n \"export_dir_fin\": \"/home/user/Downloads/completed\",\n \"file_pool_size\": 40,\n \"incomplete_files_ext\": false,\n \"ip_filter_enabled\": false,\n \"ip_filter_path\": \"\",\n \"ip_filter_trackers\": false,\n \"limit_lan_peers\": true,\n \"limit_tcp_overhead\": false,\n \"limit_utp_rate\": true,\n \"listen_port\": 58925,\n \"locale\": \"en\",\n \"lsd\": true,\n \"mail_notification_auth_enabled\": false,\n \"mail_notification_email\": \"\",\n \"mail_notification_enabled\": false,\n \"mail_notification_password\": \"\",\n \"mail_notification_sender\": \"qBittorrent_notification@example.com\",\n \"mail_notification_smtp\": \"smtp.changeme.com\",\n \"mail_notification_ssl_enabled\": false,\n \"mail_notification_username\": \"\",\n \"max_active_downloads\": 3,\n \"max_active_torrents\": 5,\n \"max_active_uploads\": 3,\n \"max_connec\": 500,\n \"max_connec_per_torrent\": 100,\n \"max_ratio\": -1,\n \"max_ratio_act\": 0,\n \"max_ratio_enabled\": false,\n \"max_seeding_time\": -1,\n \"max_seeding_time_enabled\": false,\n \"max_uploads\": -1,\n \"max_uploads_per_torrent\": -1,\n \"outgoing_ports_max\": 0,\n \"outgoing_ports_min\": 0,\n \"pex\": true,\n \"preallocate_all\": false,\n \"proxy_auth_enabled\": false,\n \"proxy_ip\": \"0.0.0.0\",\n \"proxy_password\": \"\",\n \"proxy_peer_connections\": false,\n \"proxy_port\": 8080,\n \"proxy_torrents_only\": false,\n \"proxy_type\": 0,\n \"proxy_username\": \"\",\n \"queueing_enabled\": false,\n \"random_port\": false,\n \"recheck_completed_torrents\": false,\n \"resolve_peer_countries\": true,\n \"rss_auto_downloading_enabled\":true,\n \"rss_download_repack_proper_episodes\":true,\n \"rss_max_articles_per_feed\":50,\n \"rss_processing_enabled\":true,\n \"rss_refresh_interval\":30,\n \"rss_smart_episode_filters\":\"s(\\\\d+)e(\\\\d+)\\n(\\\\d+)x(\\\\d+)\\n(\\\\d{4}[.\\\\-]\\\\d{1,2}[.\\\\-]\\\\d{1,2})\",\n \"save_path\": \"/home/user/Downloads/\",\n \"save_path_changed_tmm_enabled\": false,\n \"save_resume_data_interval\": 60,\n \"scan_dirs\":\n {\n \"/home/user/Downloads/incoming/games\": 0,\n \"/home/user/Downloads/incoming/movies\": 1,\n },\n \"schedule_from_hour\": 8,\n \"schedule_from_min\": 0,\n \"schedule_to_hour\": 20,\n \"schedule_to_min\": 0,\n \"scheduler_days\": 0,\n \"scheduler_enabled\": false,\n \"send_buffer_low_watermark\": 10,\n \"send_buffer_watermark\": 500,\n \"send_buffer_watermark_factor\": 50,\n \"slow_torrent_dl_rate_threshold\": 2,\n \"slow_torrent_inactive_timer\": 60,\n \"slow_torrent_ul_rate_threshold\": 2,\n \"socket_backlog_size\": 30,\n \"start_paused_enabled\": false,\n \"stop_tracker_timeout\": 1,\n \"temp_path\": \"/home/user/Downloads/temp\",\n \"temp_path_enabled\": false,\n \"torrent_changed_tmm_enabled\": true,\n \"up_limit\": 0,\n \"upload_choking_algorithm\": 1,\n \"upload_slots_behavior\": 0,\n \"upnp\": true,\n \"use_https\": false,\n \"utp_tcp_mixed_mode\": 0,\n \"web_ui_address\": \"*\",\n \"web_ui_ban_duration\": 3600,\n \"web_ui_clickjacking_protection_enabled\": true,\n \"web_ui_csrf_protection_enabled\": true,\n \"web_ui_custom_http_headers\": \"\",\n \"web_ui_domain_list\": \"*\",\n \"web_ui_host_header_validation_enabled\": true,\n \"web_ui_https_cert_path\": \"\",\n \"web_ui_https_key_path\": \"\",\n \"web_ui_max_auth_fail_count\": 5,\n \"web_ui_port\": 8080,\n \"web_ui_secure_cookie_enabled\": true,\n \"web_ui_session_timeout\": 3600,\n \"web_ui_upnp\": false,\n \"web_ui_use_custom_http_headers_enabled\": false,\n \"web_ui_username\": \"admin\"\n}\n```", ), - parameters: None, - return_type: Some( - ReturnType { - is_list: false, - parameters: [ - ReturnTypeParameter { - name: "locale", - description: "Currently selected language (e.g. en_GB for English)", - return_type: String( - TypeInfo { - name: "locale", - is_optional: false, - is_list: false, - description: Some( - "Currently selected language (e.g. en_GB for English)", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "create_subfolder_enabled", - description: "True if a subfolder should be created when adding a torrent", - return_type: Bool( - TypeInfo { - name: "create_subfolder_enabled", - is_optional: false, - is_list: false, - description: Some( - "True if a subfolder should be created when adding a torrent", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "start_paused_enabled", - description: "True if torrents should be added in a Paused state", - return_type: Bool( - TypeInfo { - name: "start_paused_enabled", - is_optional: false, - is_list: false, - description: Some( - "True if torrents should be added in a Paused state", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "auto_delete_mode", - description: "TODO", - return_type: Number( - TypeInfo { - name: "auto_delete_mode", - is_optional: false, - is_list: false, - description: Some( - "TODO", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "preallocate_all", - description: "True if disk space should be pre-allocated for all files", - return_type: Bool( - TypeInfo { - name: "preallocate_all", - is_optional: false, - is_list: false, - description: Some( - "True if disk space should be pre-allocated for all files", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "incomplete_files_ext", - description: "True if \".!qB\" should be appended to incomplete files", - return_type: Bool( - TypeInfo { - name: "incomplete_files_ext", - is_optional: false, - is_list: false, - description: Some( - "True if \".!qB\" should be appended to incomplete files", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "auto_tmm_enabled", - description: "True if Automatic Torrent Management is enabled by default", - return_type: Bool( - TypeInfo { - name: "auto_tmm_enabled", - is_optional: false, - is_list: false, - description: Some( - "True if Automatic Torrent Management is enabled by default", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "torrent_changed_tmm_enabled", - description: "True if torrent should be relocated when its Category changes", - return_type: Bool( - TypeInfo { - name: "torrent_changed_tmm_enabled", - is_optional: false, - is_list: false, - description: Some( - "True if torrent should be relocated when its Category changes", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "save_path_changed_tmm_enabled", - description: "True if torrent should be relocated when the default save path changes", - return_type: Bool( - TypeInfo { - name: "save_path_changed_tmm_enabled", - is_optional: false, - is_list: false, - description: Some( - "True if torrent should be relocated when the default save path changes", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "category_changed_tmm_enabled", - description: "True if torrent should be relocated when its Category's save path changes", - return_type: Bool( - TypeInfo { - name: "category_changed_tmm_enabled", - is_optional: false, - is_list: false, - description: Some( - "True if torrent should be relocated when its Category's save path changes", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "save_path", - description: "Default save path for torrents, separated by slashes", - return_type: String( - TypeInfo { - name: "save_path", - is_optional: false, - is_list: false, - description: Some( - "Default save path for torrents, separated by slashes", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "temp_path_enabled", - description: "True if folder for incomplete torrents is enabled", - return_type: Bool( - TypeInfo { - name: "temp_path_enabled", - is_optional: false, - is_list: false, - description: Some( - "True if folder for incomplete torrents is enabled", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "temp_path", - description: "Path for incomplete torrents, separated by slashes", - return_type: String( - TypeInfo { - name: "temp_path", - is_optional: false, - is_list: false, - description: Some( - "Path for incomplete torrents, separated by slashes", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "scan_dirs", - description: "Property: directory to watch for torrent files, value: where torrents loaded from this directory should be downloaded to (see list of possible values below). Slashes are used as path separators; multiple key/value pairs can be specified", - return_type: Object( - TypeInfo { - name: "scan_dirs", - is_optional: false, - is_list: false, - description: Some( - "Property: directory to watch for torrent files, value: where torrents loaded from this directory should be downloaded to (see list of possible values below). Slashes are used as path separators; multiple key/value pairs can be specified", - ), - type_description: Some( - TypeDescription { - values: [ - TypeDescriptions { - value: "0", - description: "Download to the monitored folder", - }, - TypeDescriptions { - value: "1", - description: "Download to the default save path", - }, - TypeDescriptions { - value: "\"/path/to/download/to\"", - description: "Download to this path", - }, - ], - }, - ), - }, - ), - }, - ReturnTypeParameter { - name: "export_dir", - description: "Path to directory to copy .torrent files to. Slashes are used as path separators", - return_type: String( - TypeInfo { - name: "export_dir", - is_optional: false, - is_list: false, - description: Some( - "Path to directory to copy .torrent files to. Slashes are used as path separators", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "export_dir_fin", - description: "Path to directory to copy .torrent files of completed downloads to. Slashes are used as path separators", - return_type: String( - TypeInfo { - name: "export_dir_fin", - is_optional: false, - is_list: false, - description: Some( - "Path to directory to copy .torrent files of completed downloads to. Slashes are used as path separators", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "mail_notification_enabled", - description: "True if e-mail notification should be enabled", - return_type: Bool( - TypeInfo { - name: "mail_notification_enabled", - is_optional: false, - is_list: false, - description: Some( - "True if e-mail notification should be enabled", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "mail_notification_sender", - description: "e-mail where notifications should originate from", - return_type: String( - TypeInfo { - name: "mail_notification_sender", - is_optional: false, - is_list: false, - description: Some( - "e-mail where notifications should originate from", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "mail_notification_email", - description: "e-mail to send notifications to", - return_type: String( - TypeInfo { - name: "mail_notification_email", - is_optional: false, - is_list: false, - description: Some( - "e-mail to send notifications to", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "mail_notification_smtp", - description: "smtp server for e-mail notifications", - return_type: String( - TypeInfo { - name: "mail_notification_smtp", - is_optional: false, - is_list: false, - description: Some( - "smtp server for e-mail notifications", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "mail_notification_ssl_enabled", - description: "True if smtp server requires SSL connection", - return_type: Bool( - TypeInfo { - name: "mail_notification_ssl_enabled", - is_optional: false, - is_list: false, - description: Some( - "True if smtp server requires SSL connection", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "mail_notification_auth_enabled", - description: "True if smtp server requires authentication", - return_type: Bool( - TypeInfo { - name: "mail_notification_auth_enabled", - is_optional: false, - is_list: false, - description: Some( - "True if smtp server requires authentication", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "mail_notification_username", - description: "Username for smtp authentication", - return_type: String( - TypeInfo { - name: "mail_notification_username", - is_optional: false, - is_list: false, - description: Some( - "Username for smtp authentication", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "mail_notification_password", - description: "Password for smtp authentication", - return_type: String( - TypeInfo { - name: "mail_notification_password", - is_optional: false, - is_list: false, - description: Some( - "Password for smtp authentication", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "autorun_enabled", - description: "True if external program should be run after torrent has finished downloading", - return_type: Bool( - TypeInfo { - name: "autorun_enabled", - is_optional: false, - is_list: false, - description: Some( - "True if external program should be run after torrent has finished downloading", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "autorun_program", - description: "Program path/name/arguments to run if autorun_enabled is enabled; path is separated by slashes; you can use %f and %n arguments, which will be expanded by qBittorent as path_to_torrent_file and torrent_name (from the GUI; not the .torrent file name) respectively", - return_type: String( - TypeInfo { - name: "autorun_program", - is_optional: false, - is_list: false, - description: Some( - "Program path/name/arguments to run if autorun_enabled is enabled; path is separated by slashes; you can use %f and %n arguments, which will be expanded by qBittorent as path_to_torrent_file and torrent_name (from the GUI; not the .torrent file name) respectively", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "queueing_enabled", - description: "True if torrent queuing is enabled", - return_type: Bool( - TypeInfo { - name: "queueing_enabled", - is_optional: false, - is_list: false, - description: Some( - "True if torrent queuing is enabled", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "max_active_downloads", - description: "Maximum number of active simultaneous downloads", - return_type: Number( - TypeInfo { - name: "max_active_downloads", - is_optional: false, - is_list: false, - description: Some( - "Maximum number of active simultaneous downloads", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "max_active_torrents", - description: "Maximum number of active simultaneous downloads and uploads", - return_type: Number( - TypeInfo { - name: "max_active_torrents", - is_optional: false, - is_list: false, - description: Some( - "Maximum number of active simultaneous downloads and uploads", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "max_active_uploads", - description: "Maximum number of active simultaneous uploads", - return_type: Number( - TypeInfo { - name: "max_active_uploads", - is_optional: false, - is_list: false, - description: Some( - "Maximum number of active simultaneous uploads", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "dont_count_slow_torrents", - description: "If true torrents w/o any activity (stalled ones) will not be counted towards max_active_* limits; see [dont_count_slow_torrents](https://www.libtorrent.org/reference-Settings.html#dont_count_slow_torrents) for more information", - return_type: Bool( - TypeInfo { - name: "dont_count_slow_torrents", - is_optional: false, - is_list: false, - description: Some( - "If true torrents w/o any activity (stalled ones) will not be counted towards max_active_* limits; see [dont_count_slow_torrents](https://www.libtorrent.org/reference-Settings.html#dont_count_slow_torrents) for more information", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "slow_torrent_dl_rate_threshold", - description: "Download rate in KiB/s for a torrent to be considered \"slow\"", - return_type: Number( - TypeInfo { - name: "slow_torrent_dl_rate_threshold", - is_optional: false, - is_list: false, - description: Some( - "Download rate in KiB/s for a torrent to be considered \"slow\"", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "slow_torrent_ul_rate_threshold", - description: "Upload rate in KiB/s for a torrent to be considered \"slow\"", - return_type: Number( - TypeInfo { - name: "slow_torrent_ul_rate_threshold", - is_optional: false, - is_list: false, - description: Some( - "Upload rate in KiB/s for a torrent to be considered \"slow\"", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "slow_torrent_inactive_timer", - description: "Seconds a torrent should be inactive before considered \"slow\"", - return_type: Number( - TypeInfo { - name: "slow_torrent_inactive_timer", - is_optional: false, - is_list: false, - description: Some( - "Seconds a torrent should be inactive before considered \"slow\"", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "max_ratio_enabled", - description: "True if share ratio limit is enabled", - return_type: Bool( - TypeInfo { - name: "max_ratio_enabled", - is_optional: false, - is_list: false, - description: Some( - "True if share ratio limit is enabled", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "max_ratio", - description: "Get the global share ratio limit", - return_type: Float( - TypeInfo { - name: "max_ratio", - is_optional: false, - is_list: false, - description: Some( - "Get the global share ratio limit", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "max_ratio_act", - description: "Action performed when a torrent reaches the maximum share ratio. See list of possible values here below.", - return_type: Number( - TypeInfo { - name: "max_ratio_act", - is_optional: false, - is_list: false, - description: Some( - "Action performed when a torrent reaches the maximum share ratio. See list of possible values here below.", - ), - type_description: Some( - TypeDescription { - values: [ - TypeDescriptions { - value: "0", - description: "Pause torrent", - }, - TypeDescriptions { - value: "1", - description: "Remove torrent", - }, - ], - }, - ), - }, - ), - }, - ReturnTypeParameter { - name: "listen_port", - description: "Port for incoming connections", - return_type: Number( - TypeInfo { - name: "listen_port", - is_optional: false, - is_list: false, - description: Some( - "Port for incoming connections", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "upnp", - description: "True if UPnP/NAT-PMP is enabled", - return_type: Bool( - TypeInfo { - name: "upnp", - is_optional: false, - is_list: false, - description: Some( - "True if UPnP/NAT-PMP is enabled", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "random_port", - description: "True if the port is randomly selected", - return_type: Bool( - TypeInfo { - name: "random_port", - is_optional: false, - is_list: false, - description: Some( - "True if the port is randomly selected", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "dl_limit", - description: "Global download speed limit in KiB/s; -1 means no limit is applied", - return_type: Number( - TypeInfo { - name: "dl_limit", - is_optional: false, - is_list: false, - description: Some( - "Global download speed limit in KiB/s; -1 means no limit is applied", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "up_limit", - description: "Global upload speed limit in KiB/s; -1 means no limit is applied", - return_type: Number( - TypeInfo { - name: "up_limit", - is_optional: false, - is_list: false, - description: Some( - "Global upload speed limit in KiB/s; -1 means no limit is applied", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "max_connec", - description: "Maximum global number of simultaneous connections", - return_type: Number( - TypeInfo { - name: "max_connec", - is_optional: false, - is_list: false, - description: Some( - "Maximum global number of simultaneous connections", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "max_connec_per_torrent", - description: "Maximum number of simultaneous connections per torrent", - return_type: Number( - TypeInfo { - name: "max_connec_per_torrent", - is_optional: false, - is_list: false, - description: Some( - "Maximum number of simultaneous connections per torrent", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "max_uploads", - description: "Maximum number of upload slots", - return_type: Number( - TypeInfo { - name: "max_uploads", - is_optional: false, - is_list: false, - description: Some( - "Maximum number of upload slots", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "max_uploads_per_torrent", - description: "Maximum number of upload slots per torrent", - return_type: Number( - TypeInfo { - name: "max_uploads_per_torrent", - is_optional: false, - is_list: false, - description: Some( - "Maximum number of upload slots per torrent", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "stop_tracker_timeout", - description: "Timeout in seconds for a stopped announce request to trackers", - return_type: Number( - TypeInfo { - name: "stop_tracker_timeout", - is_optional: false, - is_list: false, - description: Some( - "Timeout in seconds for a stopped announce request to trackers", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "enable_piece_extent_affinity", - description: "True if the advanced libtorrent option piece_extent_affinity is enabled", - return_type: Bool( - TypeInfo { - name: "enable_piece_extent_affinity", - is_optional: false, - is_list: false, - description: Some( - "True if the advanced libtorrent option piece_extent_affinity is enabled", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "bittorrent_protocol", - description: "Bittorrent Protocol to use (see list of possible values below)", - return_type: Number( - TypeInfo { - name: "bittorrent_protocol", - is_optional: false, - is_list: false, - description: Some( - "Bittorrent Protocol to use (see list of possible values below)", - ), - type_description: Some( - TypeDescription { - values: [ - TypeDescriptions { - value: "0", - description: "TCP and μTP", - }, - TypeDescriptions { - value: "1", - description: "TCP", - }, - TypeDescriptions { - value: "2", - description: "μTP", - }, - ], - }, - ), - }, - ), - }, - ReturnTypeParameter { - name: "limit_utp_rate", - description: "True if [du]l_limit should be applied to uTP connections; this option is only available in qBittorent built against libtorrent version 0.16.X and higher", - return_type: Bool( - TypeInfo { - name: "limit_utp_rate", - is_optional: false, - is_list: false, - description: Some( - "True if [du]l_limit should be applied to uTP connections; this option is only available in qBittorent built against libtorrent version 0.16.X and higher", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "limit_tcp_overhead", - description: "True if [du]l_limit should be applied to estimated TCP overhead (service data: e.g. packet headers)", - return_type: Bool( - TypeInfo { - name: "limit_tcp_overhead", - is_optional: false, - is_list: false, - description: Some( - "True if [du]l_limit should be applied to estimated TCP overhead (service data: e.g. packet headers)", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "limit_lan_peers", - description: "True if [du]l_limit should be applied to peers on the LAN", - return_type: Bool( - TypeInfo { - name: "limit_lan_peers", - is_optional: false, - is_list: false, - description: Some( - "True if [du]l_limit should be applied to peers on the LAN", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "alt_dl_limit", - description: "Alternative global download speed limit in KiB/s", - return_type: Number( - TypeInfo { - name: "alt_dl_limit", - is_optional: false, - is_list: false, - description: Some( - "Alternative global download speed limit in KiB/s", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "alt_up_limit", - description: "Alternative global upload speed limit in KiB/s", - return_type: Number( - TypeInfo { - name: "alt_up_limit", - is_optional: false, - is_list: false, - description: Some( - "Alternative global upload speed limit in KiB/s", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "scheduler_enabled", - description: "True if alternative limits should be applied according to schedule", - return_type: Bool( - TypeInfo { - name: "scheduler_enabled", - is_optional: false, - is_list: false, - description: Some( - "True if alternative limits should be applied according to schedule", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "schedule_from_hour", - description: "Scheduler starting hour", - return_type: Number( - TypeInfo { - name: "schedule_from_hour", - is_optional: false, - is_list: false, - description: Some( - "Scheduler starting hour", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "schedule_from_min", - description: "Scheduler starting minute", - return_type: Number( - TypeInfo { - name: "schedule_from_min", - is_optional: false, - is_list: false, - description: Some( - "Scheduler starting minute", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "schedule_to_hour", - description: "Scheduler ending hour", - return_type: Number( - TypeInfo { - name: "schedule_to_hour", - is_optional: false, - is_list: false, - description: Some( - "Scheduler ending hour", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "schedule_to_min", - description: "Scheduler ending minute", - return_type: Number( - TypeInfo { - name: "schedule_to_min", - is_optional: false, - is_list: false, - description: Some( - "Scheduler ending minute", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "scheduler_days", - description: "Scheduler days. See possible values here below", - return_type: Number( - TypeInfo { - name: "scheduler_days", - is_optional: false, - is_list: false, - description: Some( - "Scheduler days. See possible values here below", - ), - type_description: Some( - TypeDescription { - values: [ - TypeDescriptions { - value: "0", - description: "Every day", - }, - TypeDescriptions { - value: "1", - description: "Every weekday", - }, - TypeDescriptions { - value: "2", - description: "Every weekend", - }, - TypeDescriptions { - value: "3", - description: "Every Monday", - }, - TypeDescriptions { - value: "4", - description: "Every Tuesday", - }, - TypeDescriptions { - value: "5", - description: "Every Wednesday", - }, - TypeDescriptions { - value: "6", - description: "Every Thursday", - }, - TypeDescriptions { - value: "7", - description: "Every Friday", - }, - TypeDescriptions { - value: "8", - description: "Every Saturday", - }, - TypeDescriptions { - value: "9", - description: "Every Sunday", - }, - ], - }, - ), - }, - ), - }, - ReturnTypeParameter { - name: "dht", - description: "True if DHT is enabled", - return_type: Bool( - TypeInfo { - name: "dht", - is_optional: false, - is_list: false, - description: Some( - "True if DHT is enabled", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "pex", - description: "True if PeX is enabled", - return_type: Bool( - TypeInfo { - name: "pex", - is_optional: false, - is_list: false, - description: Some( - "True if PeX is enabled", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "lsd", - description: "True if LSD is enabled", - return_type: Bool( - TypeInfo { - name: "lsd", - is_optional: false, - is_list: false, - description: Some( - "True if LSD is enabled", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "encryption", - description: "See list of possible values here below", - return_type: Number( - TypeInfo { - name: "encryption", - is_optional: false, - is_list: false, - description: Some( - "See list of possible values here below", - ), - type_description: Some( - TypeDescription { - values: [ - TypeDescriptions { - value: "0", - description: "Prefer encryption", - }, - TypeDescriptions { - value: "1", - description: "Force encryption on", - }, - TypeDescriptions { - value: "2", - description: "Force encryption off", - }, - ], - }, - ), - }, - ), - }, - ReturnTypeParameter { - name: "anonymous_mode", - description: "If true anonymous mode will be enabled; read more [here](Anonymous-Mode); this option is only available in qBittorent built against libtorrent version 0.16.X and higher", - return_type: Bool( - TypeInfo { - name: "anonymous_mode", - is_optional: false, - is_list: false, - description: Some( - "If true anonymous mode will be enabled; read more [here](Anonymous-Mode); this option is only available in qBittorent built against libtorrent version 0.16.X and higher", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "proxy_type", - description: "See list of possible values here below", - return_type: Number( - TypeInfo { - name: "proxy_type", - is_optional: false, - is_list: false, - description: Some( - "See list of possible values here below", - ), - type_description: Some( - TypeDescription { - values: [ - TypeDescriptions { - value: "-1", - description: "Proxy is disabled", - }, - TypeDescriptions { - value: "1", - description: "HTTP proxy without authentication", - }, - TypeDescriptions { - value: "2", - description: "SOCKS5 proxy without authentication", - }, - TypeDescriptions { - value: "3", - description: "HTTP proxy with authentication", - }, - TypeDescriptions { - value: "4", - description: "SOCKS5 proxy with authentication", - }, - TypeDescriptions { - value: "5", - description: "SOCKS4 proxy without authentication", - }, - ], - }, - ), - }, - ), - }, - ReturnTypeParameter { - name: "proxy_ip", - description: "Proxy IP address or domain name", - return_type: String( - TypeInfo { - name: "proxy_ip", - is_optional: false, - is_list: false, - description: Some( - "Proxy IP address or domain name", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "proxy_port", - description: "Proxy port", - return_type: Number( - TypeInfo { - name: "proxy_port", - is_optional: false, - is_list: false, - description: Some( - "Proxy port", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "proxy_peer_connections", - description: "True if peer and web seed connections should be proxified; this option will have any effect only in qBittorent built against libtorrent version 0.16.X and higher", - return_type: Bool( - TypeInfo { - name: "proxy_peer_connections", - is_optional: false, - is_list: false, - description: Some( - "True if peer and web seed connections should be proxified; this option will have any effect only in qBittorent built against libtorrent version 0.16.X and higher", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "proxy_auth_enabled", - description: "True proxy requires authentication; doesn't apply to SOCKS4 proxies", - return_type: Bool( - TypeInfo { - name: "proxy_auth_enabled", - is_optional: false, - is_list: false, - description: Some( - "True proxy requires authentication; doesn't apply to SOCKS4 proxies", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "proxy_username", - description: "Username for proxy authentication", - return_type: String( - TypeInfo { - name: "proxy_username", - is_optional: false, - is_list: false, - description: Some( - "Username for proxy authentication", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "proxy_password", - description: "Password for proxy authentication", - return_type: String( - TypeInfo { - name: "proxy_password", - is_optional: false, - is_list: false, - description: Some( - "Password for proxy authentication", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "proxy_torrents_only", - description: "True if proxy is only used for torrents", - return_type: Bool( - TypeInfo { - name: "proxy_torrents_only", - is_optional: false, - is_list: false, - description: Some( - "True if proxy is only used for torrents", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "ip_filter_enabled", - description: "True if external IP filter should be enabled", - return_type: Bool( - TypeInfo { - name: "ip_filter_enabled", - is_optional: false, - is_list: false, - description: Some( - "True if external IP filter should be enabled", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "ip_filter_path", - description: "Path to IP filter file (.dat, .p2p, .p2b files are supported); path is separated by slashes", - return_type: String( - TypeInfo { - name: "ip_filter_path", - is_optional: false, - is_list: false, - description: Some( - "Path to IP filter file (.dat, .p2p, .p2b files are supported); path is separated by slashes", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "ip_filter_trackers", - description: "True if IP filters are applied to trackers", - return_type: Bool( - TypeInfo { - name: "ip_filter_trackers", - is_optional: false, - is_list: false, - description: Some( - "True if IP filters are applied to trackers", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "web_ui_domain_list", - description: "Comma-separated list of domains to accept when performing Host header validation", - return_type: String( - TypeInfo { - name: "web_ui_domain_list", - is_optional: false, - is_list: false, - description: Some( - "Comma-separated list of domains to accept when performing Host header validation", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "web_ui_address", - description: "IP address to use for the WebUI", - return_type: String( - TypeInfo { - name: "web_ui_address", - is_optional: false, - is_list: false, - description: Some( - "IP address to use for the WebUI", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "web_ui_port", - description: "WebUI port", - return_type: Number( - TypeInfo { - name: "web_ui_port", - is_optional: false, - is_list: false, - description: Some( - "WebUI port", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "web_ui_upnp", - description: "True if UPnP is used for the WebUI port", - return_type: Bool( - TypeInfo { - name: "web_ui_upnp", - is_optional: false, - is_list: false, - description: Some( - "True if UPnP is used for the WebUI port", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "web_ui_username", - description: "WebUI username", - return_type: String( - TypeInfo { - name: "web_ui_username", - is_optional: false, - is_list: false, - description: Some( - "WebUI username", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "web_ui_password", - description: "For API ≥ v2.3.0: Plaintext WebUI password, not readable, write-only. For API < v2.3.0: MD5 hash of WebUI password, hash is generated from the following string: username:Web UI Access:plain_text_web_ui_password", - return_type: String( - TypeInfo { - name: "web_ui_password", - is_optional: false, - is_list: false, - description: Some( - "For API ≥ v2.3.0: Plaintext WebUI password, not readable, write-only. For API < v2.3.0: MD5 hash of WebUI password, hash is generated from the following string: username:Web UI Access:plain_text_web_ui_password", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "web_ui_csrf_protection_enabled", - description: "True if WebUI CSRF protection is enabled", - return_type: Bool( - TypeInfo { - name: "web_ui_csrf_protection_enabled", - is_optional: false, - is_list: false, - description: Some( - "True if WebUI CSRF protection is enabled", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "web_ui_clickjacking_protection_enabled", - description: "True if WebUI clickjacking protection is enabled", - return_type: Bool( - TypeInfo { - name: "web_ui_clickjacking_protection_enabled", - is_optional: false, - is_list: false, - description: Some( - "True if WebUI clickjacking protection is enabled", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "web_ui_secure_cookie_enabled", - description: "True if WebUI cookie Secure flag is enabled", - return_type: Bool( - TypeInfo { - name: "web_ui_secure_cookie_enabled", - is_optional: false, - is_list: false, - description: Some( - "True if WebUI cookie Secure flag is enabled", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "web_ui_max_auth_fail_count", - description: "Maximum number of authentication failures before WebUI access ban", - return_type: Number( - TypeInfo { - name: "web_ui_max_auth_fail_count", - is_optional: false, - is_list: false, - description: Some( - "Maximum number of authentication failures before WebUI access ban", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "web_ui_ban_duration", - description: "WebUI access ban duration in seconds", - return_type: Number( - TypeInfo { - name: "web_ui_ban_duration", - is_optional: false, - is_list: false, - description: Some( - "WebUI access ban duration in seconds", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "web_ui_session_timeout", - description: "Seconds until WebUI is automatically signed off", - return_type: Number( - TypeInfo { - name: "web_ui_session_timeout", - is_optional: false, - is_list: false, - description: Some( - "Seconds until WebUI is automatically signed off", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "web_ui_host_header_validation_enabled", - description: "True if WebUI host header validation is enabled", - return_type: Bool( - TypeInfo { - name: "web_ui_host_header_validation_enabled", - is_optional: false, - is_list: false, - description: Some( - "True if WebUI host header validation is enabled", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "bypass_local_auth", - description: "True if authentication challenge for loopback address (127.0.0.1) should be disabled", - return_type: Bool( - TypeInfo { - name: "bypass_local_auth", - is_optional: false, - is_list: false, - description: Some( - "True if authentication challenge for loopback address (127.0.0.1) should be disabled", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "bypass_auth_subnet_whitelist_enabled", - description: "True if webui authentication should be bypassed for clients whose ip resides within (at least) one of the subnets on the whitelist", - return_type: Bool( - TypeInfo { - name: "bypass_auth_subnet_whitelist_enabled", - is_optional: false, - is_list: false, - description: Some( - "True if webui authentication should be bypassed for clients whose ip resides within (at least) one of the subnets on the whitelist", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "bypass_auth_subnet_whitelist", - description: "(White)list of ipv4/ipv6 subnets for which webui authentication should be bypassed; list entries are separated by commas", - return_type: String( - TypeInfo { - name: "bypass_auth_subnet_whitelist", - is_optional: false, - is_list: false, - description: Some( - "(White)list of ipv4/ipv6 subnets for which webui authentication should be bypassed; list entries are separated by commas", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "alternative_webui_enabled", - description: "True if an alternative WebUI should be used", - return_type: Bool( - TypeInfo { - name: "alternative_webui_enabled", - is_optional: false, - is_list: false, - description: Some( - "True if an alternative WebUI should be used", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "alternative_webui_path", - description: "File path to the alternative WebUI", - return_type: String( - TypeInfo { - name: "alternative_webui_path", - is_optional: false, - is_list: false, - description: Some( - "File path to the alternative WebUI", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "use_https", - description: "True if WebUI HTTPS access is enabled", - return_type: Bool( - TypeInfo { - name: "use_https", - is_optional: false, - is_list: false, - description: Some( - "True if WebUI HTTPS access is enabled", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "ssl_key", - description: "For API < v2.0.1: SSL keyfile contents (this is a not a path)", - return_type: String( - TypeInfo { - name: "ssl_key", - is_optional: false, - is_list: false, - description: Some( - "For API < v2.0.1: SSL keyfile contents (this is a not a path)", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "ssl_cert", - description: "For API < v2.0.1: SSL certificate contents (this is a not a path)", - return_type: String( - TypeInfo { - name: "ssl_cert", - is_optional: false, - is_list: false, - description: Some( - "For API < v2.0.1: SSL certificate contents (this is a not a path)", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "web_ui_https_key_path", - description: "For API ≥ v2.0.1: Path to SSL keyfile", - return_type: String( - TypeInfo { - name: "web_ui_https_key_path", - is_optional: false, - is_list: false, - description: Some( - "For API ≥ v2.0.1: Path to SSL keyfile", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "web_ui_https_cert_path", - description: "For API ≥ v2.0.1: Path to SSL certificate", - return_type: String( - TypeInfo { - name: "web_ui_https_cert_path", - is_optional: false, - is_list: false, - description: Some( - "For API ≥ v2.0.1: Path to SSL certificate", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "dyndns_enabled", - description: "True if server DNS should be updated dynamically", - return_type: Bool( - TypeInfo { - name: "dyndns_enabled", - is_optional: false, - is_list: false, - description: Some( - "True if server DNS should be updated dynamically", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "dyndns_service", - description: "See list of possible values here below", - return_type: Number( - TypeInfo { - name: "dyndns_service", - is_optional: false, - is_list: false, - description: Some( - "See list of possible values here below", - ), - type_description: Some( - TypeDescription { - values: [ - TypeDescriptions { - value: "0", - description: "Use DyDNS", - }, - TypeDescriptions { - value: "1", - description: "Use NOIP", - }, - ], - }, - ), - }, - ), - }, - ReturnTypeParameter { - name: "dyndns_username", - description: "Username for DDNS service", - return_type: String( - TypeInfo { - name: "dyndns_username", - is_optional: false, - is_list: false, - description: Some( - "Username for DDNS service", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "dyndns_password", - description: "Password for DDNS service", - return_type: String( - TypeInfo { - name: "dyndns_password", - is_optional: false, - is_list: false, - description: Some( - "Password for DDNS service", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "dyndns_domain", - description: "Your DDNS domain name", - return_type: String( - TypeInfo { - name: "dyndns_domain", - is_optional: false, - is_list: false, - description: Some( - "Your DDNS domain name", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "rss_refresh_interval", - description: "RSS refresh interval", - return_type: Number( - TypeInfo { - name: "rss_refresh_interval", - is_optional: false, - is_list: false, - description: Some( - "RSS refresh interval", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "rss_max_articles_per_feed", - description: "Max stored articles per RSS feed", - return_type: Number( - TypeInfo { - name: "rss_max_articles_per_feed", - is_optional: false, - is_list: false, - description: Some( - "Max stored articles per RSS feed", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "rss_processing_enabled", - description: "Enable processing of RSS feeds", - return_type: Bool( - TypeInfo { - name: "rss_processing_enabled", - is_optional: false, - is_list: false, - description: Some( - "Enable processing of RSS feeds", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "rss_auto_downloading_enabled", - description: "Enable auto-downloading of torrents from the RSS feeds", - return_type: Bool( - TypeInfo { - name: "rss_auto_downloading_enabled", - is_optional: false, - is_list: false, - description: Some( - "Enable auto-downloading of torrents from the RSS feeds", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "rss_download_repack_proper_episodes", - description: "For API ≥ v2.5.1: Enable downloading of repack/proper Episodes", - return_type: Bool( - TypeInfo { - name: "rss_download_repack_proper_episodes", - is_optional: false, - is_list: false, - description: Some( - "For API ≥ v2.5.1: Enable downloading of repack/proper Episodes", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "rss_smart_episode_filters", - description: "For API ≥ v2.5.1: List of RSS Smart Episode Filters", - return_type: String( - TypeInfo { - name: "rss_smart_episode_filters", - is_optional: false, - is_list: false, - description: Some( - "For API ≥ v2.5.1: List of RSS Smart Episode Filters", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "add_trackers_enabled", - description: "Enable automatic adding of trackers to new torrents", - return_type: Bool( - TypeInfo { - name: "add_trackers_enabled", - is_optional: false, - is_list: false, - description: Some( - "Enable automatic adding of trackers to new torrents", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "add_trackers", - description: "List of trackers to add to new torrent", - return_type: String( - TypeInfo { - name: "add_trackers", - is_optional: false, - is_list: false, - description: Some( - "List of trackers to add to new torrent", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "web_ui_use_custom_http_headers_enabled", - description: "For API ≥ v2.5.1: Enable custom http headers", - return_type: Bool( - TypeInfo { - name: "web_ui_use_custom_http_headers_enabled", - is_optional: false, - is_list: false, - description: Some( - "For API ≥ v2.5.1: Enable custom http headers", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "web_ui_custom_http_headers", - description: "For API ≥ v2.5.1: List of custom http headers", - return_type: String( - TypeInfo { - name: "web_ui_custom_http_headers", - is_optional: false, - is_list: false, - description: Some( - "For API ≥ v2.5.1: List of custom http headers", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "max_seeding_time_enabled", - description: "True enables max seeding time", - return_type: Bool( - TypeInfo { - name: "max_seeding_time_enabled", - is_optional: false, - is_list: false, - description: Some( - "True enables max seeding time", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "max_seeding_time", - description: "Number of minutes to seed a torrent", - return_type: Number( - TypeInfo { - name: "max_seeding_time", - is_optional: false, - is_list: false, - description: Some( - "Number of minutes to seed a torrent", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "announce_ip", - description: "TODO", - return_type: String( - TypeInfo { - name: "announce_ip", - is_optional: false, - is_list: false, - description: Some( - "TODO", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "announce_to_all_tiers", - description: "True always announce to all tiers", - return_type: Bool( - TypeInfo { - name: "announce_to_all_tiers", - is_optional: false, - is_list: false, - description: Some( - "True always announce to all tiers", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "announce_to_all_trackers", - description: "True always announce to all trackers in a tier", - return_type: Bool( - TypeInfo { - name: "announce_to_all_trackers", - is_optional: false, - is_list: false, - description: Some( - "True always announce to all trackers in a tier", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "async_io_threads", - description: "Number of asynchronous I/O threads", - return_type: Number( - TypeInfo { - name: "async_io_threads", - is_optional: false, - is_list: false, - description: Some( - "Number of asynchronous I/O threads", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "banned_IPs", - description: "List of banned IPs", - return_type: String( - TypeInfo { - name: "banned_IPs", - is_optional: false, - is_list: false, - description: Some( - "List of banned IPs", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "checking_memory_use", - description: "Outstanding memory when checking torrents in MiB", - return_type: Number( - TypeInfo { - name: "checking_memory_use", - is_optional: false, - is_list: false, - description: Some( - "Outstanding memory when checking torrents in MiB", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "current_interface_address", - description: "IP Address to bind to. Empty String means All addresses", - return_type: String( - TypeInfo { - name: "current_interface_address", - is_optional: false, - is_list: false, - description: Some( - "IP Address to bind to. Empty String means All addresses", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "current_network_interface", - description: "Network Interface used", - return_type: String( - TypeInfo { - name: "current_network_interface", - is_optional: false, - is_list: false, - description: Some( - "Network Interface used", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "disk_cache", - description: "Disk cache used in MiB", - return_type: Number( - TypeInfo { - name: "disk_cache", - is_optional: false, - is_list: false, - description: Some( - "Disk cache used in MiB", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "disk_cache_ttl", - description: "Disk cache expiry interval in seconds", - return_type: Number( - TypeInfo { - name: "disk_cache_ttl", - is_optional: false, - is_list: false, - description: Some( - "Disk cache expiry interval in seconds", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "embedded_tracker_port", - description: "Port used for embedded tracker", - return_type: Number( - TypeInfo { - name: "embedded_tracker_port", - is_optional: false, - is_list: false, - description: Some( - "Port used for embedded tracker", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "enable_coalesce_read_write", - description: "True enables coalesce reads & writes", - return_type: Bool( - TypeInfo { - name: "enable_coalesce_read_write", - is_optional: false, - is_list: false, - description: Some( - "True enables coalesce reads & writes", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "enable_embedded_tracker", - description: "True enables embedded tracker", - return_type: Bool( - TypeInfo { - name: "enable_embedded_tracker", - is_optional: false, - is_list: false, - description: Some( - "True enables embedded tracker", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "enable_multi_connections_from_same_ip", - description: "True allows multiple connections from the same IP address", - return_type: Bool( - TypeInfo { - name: "enable_multi_connections_from_same_ip", - is_optional: false, - is_list: false, - description: Some( - "True allows multiple connections from the same IP address", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "enable_os_cache", - description: "True enables os cache", - return_type: Bool( - TypeInfo { - name: "enable_os_cache", - is_optional: false, - is_list: false, - description: Some( - "True enables os cache", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "enable_upload_suggestions", - description: "True enables sending of upload piece suggestions", - return_type: Bool( - TypeInfo { - name: "enable_upload_suggestions", - is_optional: false, - is_list: false, - description: Some( - "True enables sending of upload piece suggestions", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "file_pool_size", - description: "File pool size", - return_type: Number( - TypeInfo { - name: "file_pool_size", - is_optional: false, - is_list: false, - description: Some( - "File pool size", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "outgoing_ports_max", - description: "Maximal outgoing port (0: Disabled)", - return_type: Number( - TypeInfo { - name: "outgoing_ports_max", - is_optional: false, - is_list: false, - description: Some( - "Maximal outgoing port (0: Disabled)", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "outgoing_ports_min", - description: "Minimal outgoing port (0: Disabled)", - return_type: Number( - TypeInfo { - name: "outgoing_ports_min", - is_optional: false, - is_list: false, - description: Some( - "Minimal outgoing port (0: Disabled)", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "recheck_completed_torrents", - description: "True rechecks torrents on completion", - return_type: Bool( - TypeInfo { - name: "recheck_completed_torrents", - is_optional: false, - is_list: false, - description: Some( - "True rechecks torrents on completion", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "resolve_peer_countries", - description: "True resolves peer countries", - return_type: Bool( - TypeInfo { - name: "resolve_peer_countries", - is_optional: false, - is_list: false, - description: Some( - "True resolves peer countries", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "save_resume_data_interval", - description: "Save resume data interval in min", - return_type: Number( - TypeInfo { - name: "save_resume_data_interval", - is_optional: false, - is_list: false, - description: Some( - "Save resume data interval in min", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "send_buffer_low_watermark", - description: "Send buffer low watermark in KiB", - return_type: Number( - TypeInfo { - name: "send_buffer_low_watermark", - is_optional: false, - is_list: false, - description: Some( - "Send buffer low watermark in KiB", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "send_buffer_watermark", - description: "Send buffer watermark in KiB", - return_type: Number( - TypeInfo { - name: "send_buffer_watermark", - is_optional: false, - is_list: false, - description: Some( - "Send buffer watermark in KiB", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "send_buffer_watermark_factor", - description: "Send buffer watermark factor in percent", - return_type: Number( - TypeInfo { - name: "send_buffer_watermark_factor", - is_optional: false, - is_list: false, - description: Some( - "Send buffer watermark factor in percent", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "socket_backlog_size", - description: "Socket backlog size", - return_type: Number( - TypeInfo { - name: "socket_backlog_size", - is_optional: false, - is_list: false, - description: Some( - "Socket backlog size", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "upload_choking_algorithm", - description: "Upload choking algorithm used (see list of possible values below)", - return_type: Number( - TypeInfo { - name: "upload_choking_algorithm", - is_optional: false, - is_list: false, - description: Some( - "Upload choking algorithm used (see list of possible values below)", - ), - type_description: Some( - TypeDescription { - values: [ - TypeDescriptions { - value: "0", - description: "Round-robin", - }, - TypeDescriptions { - value: "1", - description: "Fastest upload", - }, - TypeDescriptions { - value: "2", - description: "Anti-leech", - }, - ], - }, - ), - }, - ), - }, - ReturnTypeParameter { - name: "upload_slots_behavior", - description: "Upload slots behavior used (see list of possible values below)", - return_type: Number( - TypeInfo { - name: "upload_slots_behavior", - is_optional: false, - is_list: false, - description: Some( - "Upload slots behavior used (see list of possible values below)", - ), - type_description: Some( - TypeDescription { - values: [ - TypeDescriptions { - value: "0", - description: "Fixed slots", - }, - TypeDescriptions { - value: "1", - description: "Upload rate based", - }, - ], - }, - ), - }, - ), - }, - ReturnTypeParameter { - name: "upnp_lease_duration", - description: "UPnP lease duration (0: Permanent lease)", - return_type: Number( - TypeInfo { - name: "upnp_lease_duration", - is_optional: false, - is_list: false, - description: Some( - "UPnP lease duration (0: Permanent lease)", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "utp_tcp_mixed_mode", - description: "μTP-TCP mixed mode algorithm (see list of possible values below)", - return_type: Number( - TypeInfo { - name: "utp_tcp_mixed_mode", - is_optional: false, - is_list: false, - description: Some( - "μTP-TCP mixed mode algorithm (see list of possible values below)", - ), - type_description: Some( - TypeDescription { - values: [ - TypeDescriptions { - value: "0", - description: "Prefer TCP", - }, - TypeDescriptions { - value: "1", - description: "Peer proportional", - }, - ], - }, - ), - }, - ), - }, - ], - }, - ), url: "preferences", + types: CompositeTypes { + composite_types: [ + Enum( + Enum { + name: "BittorrentProtocol", + values: [ + EnumValue { + description: Some( + "TCP and μTP", + ), + value: "TCPAndμTP", + original_value: "0", + }, + EnumValue { + description: Some( + "TCP", + ), + value: "TCP", + original_value: "1", + }, + EnumValue { + description: Some( + "μTP", + ), + value: "μTP", + original_value: "2", + }, + ], + }, + ), + Enum( + Enum { + name: "DyndnsService", + values: [ + EnumValue { + description: Some( + "Use DyDNS", + ), + value: "UseDyDNS", + original_value: "0", + }, + EnumValue { + description: Some( + "Use NOIP", + ), + value: "UseNOIP", + original_value: "1", + }, + ], + }, + ), + Enum( + Enum { + name: "Encryption", + values: [ + EnumValue { + description: Some( + "Prefer encryption", + ), + value: "PreferEncryption", + original_value: "0", + }, + EnumValue { + description: Some( + "Force encryption on", + ), + value: "ForceEncryptionOn", + original_value: "1", + }, + EnumValue { + description: Some( + "Force encryption off", + ), + value: "ForceEncryptionOff", + original_value: "2", + }, + ], + }, + ), + Enum( + Enum { + name: "MaxRatioAct", + values: [ + EnumValue { + description: Some( + "Pause torrent", + ), + value: "PauseTorrent", + original_value: "0", + }, + EnumValue { + description: Some( + "Remove torrent", + ), + value: "RemoveTorrent", + original_value: "1", + }, + ], + }, + ), + Enum( + Enum { + name: "ProxyType", + values: [ + EnumValue { + description: Some( + "Proxy is disabled", + ), + value: "ProxyIsDisabled", + original_value: "-1", + }, + EnumValue { + description: Some( + "HTTP proxy without authentication", + ), + value: "HTTPProxyWithoutAuthentication", + original_value: "1", + }, + EnumValue { + description: Some( + "SOCKS5 proxy without authentication", + ), + value: "SOCKS5ProxyWithoutAuthentication", + original_value: "2", + }, + EnumValue { + description: Some( + "HTTP proxy with authentication", + ), + value: "HTTPProxyWithAuthentication", + original_value: "3", + }, + EnumValue { + description: Some( + "SOCKS5 proxy with authentication", + ), + value: "SOCKS5ProxyWithAuthentication", + original_value: "4", + }, + EnumValue { + description: Some( + "SOCKS4 proxy without authentication", + ), + value: "SOCKS4ProxyWithoutAuthentication", + original_value: "5", + }, + ], + }, + ), + Enum( + Enum { + name: "ScanDirs", + values: [ + EnumValue { + description: Some( + "Download to the monitored folder", + ), + value: "DownloadToTheMonitoredFolder", + original_value: "0", + }, + EnumValue { + description: Some( + "Download to the default save path", + ), + value: "DownloadToTheDefaultSavePath", + original_value: "1", + }, + EnumValue { + description: Some( + "Download to this path", + ), + value: "\"/path/to/download/to\"", + original_value: "\"/path/to/download/to\"", + }, + ], + }, + ), + Enum( + Enum { + name: "SchedulerDays", + values: [ + EnumValue { + description: Some( + "Every day", + ), + value: "EveryDay", + original_value: "0", + }, + EnumValue { + description: Some( + "Every weekday", + ), + value: "EveryWeekday", + original_value: "1", + }, + EnumValue { + description: Some( + "Every weekend", + ), + value: "EveryWeekend", + original_value: "2", + }, + EnumValue { + description: Some( + "Every Monday", + ), + value: "EveryMonday", + original_value: "3", + }, + EnumValue { + description: Some( + "Every Tuesday", + ), + value: "EveryTuesday", + original_value: "4", + }, + EnumValue { + description: Some( + "Every Wednesday", + ), + value: "EveryWednesday", + original_value: "5", + }, + EnumValue { + description: Some( + "Every Thursday", + ), + value: "EveryThursday", + original_value: "6", + }, + EnumValue { + description: Some( + "Every Friday", + ), + value: "EveryFriday", + original_value: "7", + }, + EnumValue { + description: Some( + "Every Saturday", + ), + value: "EverySaturday", + original_value: "8", + }, + EnumValue { + description: Some( + "Every Sunday", + ), + value: "EverySunday", + original_value: "9", + }, + ], + }, + ), + Enum( + Enum { + name: "UploadChokingAlgorithm", + values: [ + EnumValue { + description: Some( + "Round-robin", + ), + value: "RoundRobin", + original_value: "0", + }, + EnumValue { + description: Some( + "Fastest upload", + ), + value: "FastestUpload", + original_value: "1", + }, + EnumValue { + description: Some( + "Anti-leech", + ), + value: "AntiLeech", + original_value: "2", + }, + ], + }, + ), + Enum( + Enum { + name: "UploadSlotsBehavior", + values: [ + EnumValue { + description: Some( + "Fixed slots", + ), + value: "FixedSlots", + original_value: "0", + }, + EnumValue { + description: Some( + "Upload rate based", + ), + value: "UploadRateBased", + original_value: "1", + }, + ], + }, + ), + Enum( + Enum { + name: "UtpTcpMixedMode", + values: [ + EnumValue { + description: Some( + "Prefer TCP", + ), + value: "PreferTCP", + original_value: "0", + }, + EnumValue { + description: Some( + "Peer proportional", + ), + value: "PeerProportional", + original_value: "1", + }, + ], + }, + ), + ], + }, }, ApiMethod { name: "setPreferences", description: Some( "1. There is no need to pass all possible preferences' `token:value` pairs if you only want to change one option\n 1. Paths in `scan_dirs` must exist, otherwise this option will have no effect\n 1. String values must be quoted; integer and boolean values must never be quoted\n\nFor a list of possible preference options see [Get application preferences](#get-application-preferences)", ), - parameters: None, - return_type: None, url: "setPreferences", + types: CompositeTypes { + composite_types: [], + }, }, ApiMethod { name: "defaultSavePath", description: Some( "The response is a string with the default save path, e.g. `C:/Users/Dayman/Downloads`.", ), - parameters: None, - return_type: None, url: "defaultSavePath", + types: CompositeTypes { + composite_types: [], + }, }, ], description: Some( @@ -2601,162 +525,100 @@ description: Some( "The response is a JSON array in which each element is an entry of the log.\n\nEach element of the array has the following properties:\n\n\nExample:\n\n```JSON\n[\n {\n \"id\":0,\n \"message\":\"qBittorrent v3.4.0 started\",\n \"timestamp\":1507969127860,\n \"type\":1\n },\n {\n \"id\":1,\n \"message\":\"qBittorrent is trying to listen on any interface port: 19036\",\n \"timestamp\":1507969127869,\n \"type\":2\n },\n {\n \"id\":2,\n \"message\":\"Peer ID: -qB3400-\",\n \"timestamp\":1507969127870,\n \"type\":1\n },\n {\n \"id\":3,\n \"message\":\"HTTP User-Agent is 'qBittorrent/3.4.0'\",\n \"timestamp\":1507969127870,\n \"type\":1\n },\n {\n \"id\":4,\n \"message\":\"DHT support [ON]\",\n \"timestamp\":1507969127871,\n \"type\":2\n },\n {\n \"id\":5,\n \"message\":\"Local Peer Discovery support [ON]\",\n \"timestamp\":1507969127871,\n \"type\":2\n },\n {\n \"id\":6,\n \"message\":\"PeX support [ON]\",\n \"timestamp\":1507969127871,\n \"type\":2\n },\n {\n \"id\":7,\n \"message\":\"Anonymous mode [OFF]\",\n \"timestamp\":1507969127871,\n \"type\":2\n },\n {\n \"id\":8,\n \"message\":\"Encryption support [ON]\",\n \"timestamp\":1507969127871,\n \"type\":2\n },\n {\n \"id\":9,\n \"message\":\"Embedded Tracker [OFF]\",\n \"timestamp\":1507969127871,\n \"type\":2\n },\n {\n \"id\":10,\n \"message\":\"UPnP / NAT-PMP support [ON]\",\n \"timestamp\":1507969127873,\n \"type\":2\n },\n {\n \"id\":11,\n \"message\":\"Web UI: Now listening on port 8080\",\n \"timestamp\":1507969127883,\n \"type\":1\n },\n {\n \"id\":12,\n \"message\":\"Options were saved successfully.\",\n \"timestamp\":1507969128055,\n \"type\":1\n },\n {\n \"id\":13,\n \"message\":\"qBittorrent is successfully listening on interface :: port: TCP/19036\",\n \"timestamp\":1507969128270,\n \"type\":2\n },\n {\n \"id\":14,\n \"message\":\"qBittorrent is successfully listening on interface 0.0.0.0 port: TCP/19036\",\n \"timestamp\":1507969128271,\n \"type\":2\n },\n {\n \"id\":15,\n \"message\":\"qBittorrent is successfully listening on interface 0.0.0.0 port: UDP/19036\",\n \"timestamp\":1507969128272,\n \"type\":2\n }\n]\n```", ), - parameters: Some( - ApiParameters { - mandatory: [], - optional: [ - Bool( - TypeInfo { - name: "normal", - is_optional: true, - is_list: false, - description: Some( - "Include normal messages (default: true)", - ), - type_description: None, - }, - ), - Bool( - TypeInfo { - name: "info", - is_optional: true, - is_list: false, - description: Some( - "Include info messages (default: true)", - ), - type_description: None, - }, - ), - Bool( - TypeInfo { - name: "warning", - is_optional: true, - is_list: false, - description: Some( - "Include warning messages (default: true)", - ), - type_description: None, - }, - ), - Bool( - TypeInfo { - name: "critical", - is_optional: true, - is_list: false, - description: Some( - "Include critical messages (default: true)", - ), - type_description: None, - }, - ), - Number( - TypeInfo { - name: "last_known_id", - is_optional: true, - is_list: false, - description: Some( - "Exclude messages with \"message id\" <= last_known_id (default: -1)", - ), - type_description: None, - }, - ), - ], - }, - ), - return_type: Some( - ReturnType { - is_list: true, - parameters: [ - ReturnTypeParameter { - name: "id", - description: "ID of the message", - return_type: Number( - TypeInfo { - name: "id", - is_optional: false, - is_list: false, - description: Some( - "ID of the message", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "message", - description: "Text of the message", - return_type: String( - TypeInfo { - name: "message", - is_optional: false, - is_list: false, - description: Some( - "Text of the message", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "timestamp", - description: "Milliseconds since epoch", - return_type: Number( - TypeInfo { - name: "timestamp", - is_optional: false, - is_list: false, - description: Some( - "Milliseconds since epoch", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "type", - description: "Type of the message: Log::NORMAL: 1, Log::INFO: 2, Log::WARNING: 4, Log::CRITICAL: 8", - return_type: Number( - TypeInfo { - name: "type", - is_optional: false, - is_list: false, - description: Some( - "Type of the message: Log::NORMAL: 1, Log::INFO: 2, Log::WARNING: 4, Log::CRITICAL: 8", - ), - type_description: None, - }, - ), - }, - ], - }, - ), url: "main", + types: CompositeTypes { + composite_types: [ + Parameters( + TypeWithoutName { + types: [ + Bool( + TypeInfo { + name: "normal", + is_optional: true, + is_list: false, + description: Some( + "Include normal messages (default: true)", + ), + type_description: None, + }, + ), + Bool( + TypeInfo { + name: "info", + is_optional: true, + is_list: false, + description: Some( + "Include info messages (default: true)", + ), + type_description: None, + }, + ), + Bool( + TypeInfo { + name: "warning", + is_optional: true, + is_list: false, + description: Some( + "Include warning messages (default: true)", + ), + type_description: None, + }, + ), + Bool( + TypeInfo { + name: "critical", + is_optional: true, + is_list: false, + description: Some( + "Include critical messages (default: true)", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "last_known_id", + is_optional: true, + is_list: false, + description: Some( + "Exclude messages with \"message id\" <= last_known_id (default: -1)", + ), + type_description: None, + }, + ), + ], + }, + ), + ], + }, }, ApiMethod { name: "peers", description: Some( "The response a JSON array. Each element of the array of objects (each object is the information relative to a peer) containing the following fields", ), - parameters: Some( - ApiParameters { - mandatory: [], - optional: [ - Number( - TypeInfo { - name: "last_known_id", - is_optional: true, - is_list: false, - description: Some( - "Exclude messages with \"message id\" <= last_known_id (default: -1)", - ), - type_description: None, - }, - ), - ], - }, - ), - return_type: None, url: "peers", + types: CompositeTypes { + composite_types: [ + Parameters( + TypeWithoutName { + types: [ + Number( + TypeInfo { + name: "last_known_id", + is_optional: true, + is_list: false, + description: Some( + "Exclude messages with \"message id\" <= last_known_id (default: -1)", + ), + type_description: None, + }, + ), + ], + }, + ), + ], + }, }, ], description: Some( @@ -2772,204 +634,181 @@ description: Some( "The response is a JSON object with the following possible fields\n\n\nExample:\n\n```JSON\n{\n \"rid\":15,\n \"torrents\":\n {\n \"8c212779b4abde7c6bc608063a0d008b7e40ce32\":\n {\n \"state\":\"pausedUP\"\n }\n }\n}\n```", ), - parameters: Some( - ApiParameters { - mandatory: [ - Number( - TypeInfo { - name: "rid", - is_optional: false, - is_list: false, - description: Some( - "Response ID. If not provided, rid=0 will be assumed. If the given rid is different from the one of last server reply, full_update will be true (see the server reply details for more info)", - ), - type_description: None, - }, - ), - ], - optional: [], - }, - ), - return_type: Some( - ReturnType { - is_list: false, - parameters: [ - ReturnTypeParameter { - name: "rid", - description: "Response ID", - return_type: Number( - TypeInfo { - name: "rid", - is_optional: false, - is_list: false, - description: Some( - "Response ID", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "full_update", - description: "Whether the response contains all the data or partial data", - return_type: Bool( - TypeInfo { - name: "full_update", - is_optional: false, - is_list: false, - description: Some( - "Whether the response contains all the data or partial data", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "torrents", - description: "Property: torrent hash, value: same as [torrent list](#get-torrent-list)", - return_type: Object( - TypeInfo { - name: "torrents", - is_optional: false, - is_list: false, - description: Some( - "Property: torrent hash, value: same as [torrent list](#get-torrent-list)", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "torrents_removed", - description: "List of hashes of torrents removed since last request", - return_type: StringArray( - TypeInfo { - name: "torrents_removed", - is_optional: false, - is_list: false, - description: Some( - "List of hashes of torrents removed since last request", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "categories", - description: "Info for categories added since last request", - return_type: Object( - TypeInfo { - name: "categories", - is_optional: false, - is_list: false, - description: Some( - "Info for categories added since last request", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "categories_removed", - description: "List of categories removed since last request", - return_type: StringArray( - TypeInfo { - name: "categories_removed", - is_optional: false, - is_list: false, - description: Some( - "List of categories removed since last request", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "tags", - description: "List of tags added since last request", - return_type: StringArray( - TypeInfo { - name: "tags", - is_optional: false, - is_list: false, - description: Some( - "List of tags added since last request", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "tags_removed", - description: "List of tags removed since last request", - return_type: StringArray( - TypeInfo { - name: "tags_removed", - is_optional: false, - is_list: false, - description: Some( - "List of tags removed since last request", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "server_state", - description: "Global transfer info", - return_type: Object( - TypeInfo { - name: "server_state", - is_optional: false, - is_list: false, - description: Some( - "Global transfer info", - ), - type_description: None, - }, - ), - }, - ], - }, - ), url: "maindata", + types: CompositeTypes { + composite_types: [ + Parameters( + TypeWithoutName { + types: [ + Number( + TypeInfo { + name: "rid", + is_optional: false, + is_list: false, + description: Some( + "Response ID. If not provided, rid=0 will be assumed. If the given rid is different from the one of last server reply, full_update will be true (see the server reply details for more info)", + ), + type_description: None, + }, + ), + ], + }, + ), + Response( + TypeWithoutName { + types: [ + Number( + TypeInfo { + name: "rid", + is_optional: false, + is_list: false, + description: Some( + "Response ID", + ), + type_description: None, + }, + ), + Bool( + TypeInfo { + name: "full_update", + is_optional: false, + is_list: false, + description: Some( + "Whether the response contains all the data or partial data", + ), + type_description: None, + }, + ), + Object( + Object { + type_info: TypeInfo { + name: "torrents", + is_optional: false, + is_list: false, + description: Some( + "Property: torrent hash, value: same as [torrent list](#get-torrent-list)", + ), + type_description: None, + }, + ref_type: "Object", + }, + ), + StringArray( + TypeInfo { + name: "torrents_removed", + is_optional: false, + is_list: false, + description: Some( + "List of hashes of torrents removed since last request", + ), + type_description: None, + }, + ), + Object( + Object { + type_info: TypeInfo { + name: "categories", + is_optional: false, + is_list: false, + description: Some( + "Info for categories added since last request", + ), + type_description: None, + }, + ref_type: "Object", + }, + ), + StringArray( + TypeInfo { + name: "categories_removed", + is_optional: false, + is_list: false, + description: Some( + "List of categories removed since last request", + ), + type_description: None, + }, + ), + StringArray( + TypeInfo { + name: "tags", + is_optional: false, + is_list: false, + description: Some( + "List of tags added since last request", + ), + type_description: None, + }, + ), + StringArray( + TypeInfo { + name: "tags_removed", + is_optional: false, + is_list: false, + description: Some( + "List of tags removed since last request", + ), + type_description: None, + }, + ), + Object( + Object { + type_info: TypeInfo { + name: "server_state", + is_optional: false, + is_list: false, + description: Some( + "Global transfer info", + ), + type_description: None, + }, + ref_type: "Object", + }, + ), + ], + }, + ), + ], + }, }, ApiMethod { name: "torrentPeers", description: Some( "The response is TODO", ), - parameters: Some( - ApiParameters { - mandatory: [ - String( - TypeInfo { - name: "hash", - is_optional: false, - is_list: false, - description: Some( - "Torrent hash", - ), - type_description: None, - }, - ), - Number( - TypeInfo { - name: "rid", - is_optional: false, - is_list: false, - description: Some( - "Response ID. If not provided, rid=0 will be assumed. If the given rid is different from the one of last server reply, full_update will be true (see the server reply details for more info)", - ), - type_description: None, - }, - ), - ], - optional: [], - }, - ), - return_type: None, url: "torrentPeers", + types: CompositeTypes { + composite_types: [ + Parameters( + TypeWithoutName { + types: [ + String( + TypeInfo { + name: "hash", + is_optional: false, + is_list: false, + description: Some( + "Torrent hash", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "rid", + is_optional: false, + is_list: false, + description: Some( + "Response ID. If not provided, rid=0 will be assumed. If the given rid is different from the one of last server reply, full_update will be true (see the server reply details for more info)", + ), + type_description: None, + }, + ), + ], + }, + ), + ], + }, }, ], description: Some( @@ -2985,241 +824,221 @@ description: Some( "The response is a JSON object with the following fields\n\n\nIn addition to the above in partial data requests (see [Get partial data](#get-partial-data) for more info):\n\n\nPossible values of `connection_status`:\n\nValue |\n\nExample:\n\n```JSON\n{\n \"connection_status\":\"connected\",\n \"dht_nodes\":386,\n \"dl_info_data\":681521119,\n \"dl_info_speed\":0,\n \"dl_rate_limit\":0,\n \"up_info_data\":10747904,\n \"up_info_speed\":0,\n \"up_rate_limit\":1048576\n}\n```", ), - parameters: None, - return_type: Some( - ReturnType { - is_list: false, - parameters: [ - ReturnTypeParameter { - name: "dl_info_speed", - description: "Global download rate (bytes/s)", - return_type: Number( - TypeInfo { - name: "dl_info_speed", - is_optional: false, - is_list: false, - description: Some( - "Global download rate (bytes/s)", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "dl_info_data", - description: "Data downloaded this session (bytes)", - return_type: Number( - TypeInfo { - name: "dl_info_data", - is_optional: false, - is_list: false, - description: Some( - "Data downloaded this session (bytes)", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "up_info_speed", - description: "Global upload rate (bytes/s)", - return_type: Number( - TypeInfo { - name: "up_info_speed", - is_optional: false, - is_list: false, - description: Some( - "Global upload rate (bytes/s)", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "up_info_data", - description: "Data uploaded this session (bytes)", - return_type: Number( - TypeInfo { - name: "up_info_data", - is_optional: false, - is_list: false, - description: Some( - "Data uploaded this session (bytes)", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "dl_rate_limit", - description: "Download rate limit (bytes/s)", - return_type: Number( - TypeInfo { - name: "dl_rate_limit", - is_optional: false, - is_list: false, - description: Some( - "Download rate limit (bytes/s)", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "up_rate_limit", - description: "Upload rate limit (bytes/s)", - return_type: Number( - TypeInfo { - name: "up_rate_limit", - is_optional: false, - is_list: false, - description: Some( - "Upload rate limit (bytes/s)", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "dht_nodes", - description: "DHT nodes connected to", - return_type: Number( - TypeInfo { - name: "dht_nodes", - is_optional: false, - is_list: false, - description: Some( - "DHT nodes connected to", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "connection_status", - description: "Connection status. See possible values here below", - return_type: String( - TypeInfo { - name: "connection_status", - is_optional: false, - is_list: false, - description: Some( - "Connection status. See possible values here below", - ), - type_description: None, - }, - ), - }, - ], - }, - ), url: "info", + types: CompositeTypes { + composite_types: [ + Response( + TypeWithoutName { + types: [ + Number( + TypeInfo { + name: "dl_info_speed", + is_optional: false, + is_list: false, + description: Some( + "Global download rate (bytes/s)", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "dl_info_data", + is_optional: false, + is_list: false, + description: Some( + "Data downloaded this session (bytes)", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "up_info_speed", + is_optional: false, + is_list: false, + description: Some( + "Global upload rate (bytes/s)", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "up_info_data", + is_optional: false, + is_list: false, + description: Some( + "Data uploaded this session (bytes)", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "dl_rate_limit", + is_optional: false, + is_list: false, + description: Some( + "Download rate limit (bytes/s)", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "up_rate_limit", + is_optional: false, + is_list: false, + description: Some( + "Upload rate limit (bytes/s)", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "dht_nodes", + is_optional: false, + is_list: false, + description: Some( + "DHT nodes connected to", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "connection_status", + is_optional: false, + is_list: false, + description: Some( + "Connection status. See possible values here below", + ), + type_description: None, + }, + ), + ], + }, + ), + ], + }, }, ApiMethod { name: "speedLimitsMode", description: Some( "The response is `1` if alternative speed limits are enabled, `0` otherwise.", ), - parameters: None, - return_type: None, url: "speedLimitsMode", + types: CompositeTypes { + composite_types: [], + }, }, ApiMethod { name: "toggleSpeedLimitsMode", description: None, - parameters: None, - return_type: None, url: "toggleSpeedLimitsMode", + types: CompositeTypes { + composite_types: [], + }, }, ApiMethod { name: "downloadLimit", description: Some( "The response is the value of current global download speed limit in bytes/second; this value will be zero if no limit is applied.", ), - parameters: None, - return_type: None, url: "downloadLimit", + types: CompositeTypes { + composite_types: [], + }, }, ApiMethod { name: "setDownloadLimit", description: None, - parameters: Some( - ApiParameters { - mandatory: [ - Number( - TypeInfo { - name: "limit", - is_optional: false, - is_list: false, - description: Some( - "The global download speed limit to set in bytes/second", - ), - type_description: None, - }, - ), - ], - optional: [], - }, - ), - return_type: None, url: "setDownloadLimit", + types: CompositeTypes { + composite_types: [ + Parameters( + TypeWithoutName { + types: [ + Number( + TypeInfo { + name: "limit", + is_optional: false, + is_list: false, + description: Some( + "The global download speed limit to set in bytes/second", + ), + type_description: None, + }, + ), + ], + }, + ), + ], + }, }, ApiMethod { name: "uploadLimit", description: Some( "The response is the value of current global upload speed limit in bytes/second; this value will be zero if no limit is applied.", ), - parameters: None, - return_type: None, url: "uploadLimit", + types: CompositeTypes { + composite_types: [], + }, }, ApiMethod { name: "setUploadLimit", description: None, - parameters: Some( - ApiParameters { - mandatory: [ - Number( - TypeInfo { - name: "limit", - is_optional: false, - is_list: false, - description: Some( - "The global upload speed limit to set in bytes/second", - ), - type_description: None, - }, - ), - ], - optional: [], - }, - ), - return_type: None, url: "setUploadLimit", + types: CompositeTypes { + composite_types: [ + Parameters( + TypeWithoutName { + types: [ + Number( + TypeInfo { + name: "limit", + is_optional: false, + is_list: false, + description: Some( + "The global upload speed limit to set in bytes/second", + ), + type_description: None, + }, + ), + ], + }, + ), + ], + }, }, ApiMethod { name: "banPeers", description: None, - parameters: Some( - ApiParameters { - mandatory: [ - String( - TypeInfo { - name: "peers", - is_optional: false, - is_list: false, - description: Some( - "The peer to ban, or multiple peers separated by a pipe \\", - ), - type_description: None, - }, - ), - ], - optional: [], - }, - ), - return_type: None, url: "banPeers", + types: CompositeTypes { + composite_types: [ + Parameters( + TypeWithoutName { + types: [ + String( + TypeInfo { + name: "peers", + is_optional: false, + is_list: false, + description: Some( + "The peer to ban, or multiple peers separated by a pipe \\", + ), + type_description: None, + }, + ), + ], + }, + ), + ], + }, }, ], description: Some( @@ -3235,2053 +1054,2042 @@ description: Some( "The response is a JSON array with the following fields\n\n\nPossible values of `state`:\n\n\nExample:\n\n```JSON\n[\n {\n \"dlspeed\":9681262,\n \"eta\":87,\n \"f_l_piece_prio\":false,\n \"force_start\":false,\n \"hash\":\"8c212779b4abde7c6bc608063a0d008b7e40ce32\",\n \"category\":\"\",\n \"tags\": \"\",\n \"name\":\"debian-8.1.0-amd64-CD-1.iso\",\n \"num_complete\":-1,\n \"num_incomplete\":-1,\n \"num_leechs\":2,\n \"num_seeds\":54,\n \"priority\":1,\n \"progress\":0.16108787059783936,\n \"ratio\":0,\n \"seq_dl\":false,\n \"size\":657457152,\n \"state\":\"downloading\",\n \"super_seeding\":false,\n \"upspeed\":0\n },\n {\n another_torrent_info\n }\n]\n```", ), - parameters: Some( - ApiParameters { - mandatory: [], - optional: [ - String( - TypeInfo { - name: "filter", - is_optional: true, - is_list: false, - description: Some( - "Filter torrent list by state. Allowed state filters: all, downloading, seeding, completed, paused, active, inactive, resumed, stalled, stalled_uploading, stalled_downloading, errored", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "category", - is_optional: true, - is_list: false, - description: Some( - "Get torrents with the given category (empty string means \"without category\"; no \"category\" parameter means \"any category\" <- broken until [#11748](https://github.com/qbittorrent/qBittorrent/issues/11748) is resolved). Remember to URL-encode the category name. For example, My category becomes My%20category", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "tag", - is_optional: true, - is_list: false, - description: Some( - "Get torrents with the given tag (empty string means \"without tag\"; no \"tag\" parameter means \"any tag\". Remember to URL-encode the category name. For example, My tag becomes My%20tag", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "sort", - is_optional: true, - is_list: false, - description: Some( - "Sort torrents by given key. They can be sorted using any field of the response's JSON array (which are documented below) as the sort key.", - ), - type_description: None, - }, - ), - Bool( - TypeInfo { - name: "reverse", - is_optional: true, - is_list: false, - description: Some( - "Enable reverse sorting. Defaults to false", - ), - type_description: None, - }, - ), - Number( - TypeInfo { - name: "limit", - is_optional: true, - is_list: false, - description: Some( - "Limit the number of torrents returned", - ), - type_description: None, - }, - ), - Number( - TypeInfo { - name: "offset", - is_optional: true, - is_list: false, - description: Some( - "Set offset (if less than 0, offset from end)", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "hashes", - is_optional: true, - is_list: false, - description: Some( - "Filter by hashes. Can contain multiple hashes separated by \\", - ), - type_description: None, - }, - ), - ], - }, - ), - return_type: Some( - ReturnType { - is_list: true, - parameters: [ - ReturnTypeParameter { - name: "added_on", - description: "Time (Unix Epoch) when the torrent was added to the client", - return_type: Number( - TypeInfo { - name: "added_on", - is_optional: false, - is_list: false, - description: Some( - "Time (Unix Epoch) when the torrent was added to the client", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "amount_left", - description: "Amount of data left to download (bytes)", - return_type: Number( - TypeInfo { - name: "amount_left", - is_optional: false, - is_list: false, - description: Some( - "Amount of data left to download (bytes)", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "auto_tmm", - description: "Whether this torrent is managed by Automatic Torrent Management", - return_type: Bool( - TypeInfo { - name: "auto_tmm", - is_optional: false, - is_list: false, - description: Some( - "Whether this torrent is managed by Automatic Torrent Management", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "availability", - description: "Percentage of file pieces currently available", - return_type: Float( - TypeInfo { - name: "availability", - is_optional: false, - is_list: false, - description: Some( - "Percentage of file pieces currently available", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "category", - description: "Category of the torrent", - return_type: String( - TypeInfo { - name: "category", - is_optional: false, - is_list: false, - description: Some( - "Category of the torrent", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "completed", - description: "Amount of transfer data completed (bytes)", - return_type: Number( - TypeInfo { - name: "completed", - is_optional: false, - is_list: false, - description: Some( - "Amount of transfer data completed (bytes)", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "completion_on", - description: "Time (Unix Epoch) when the torrent completed", - return_type: Number( - TypeInfo { - name: "completion_on", - is_optional: false, - is_list: false, - description: Some( - "Time (Unix Epoch) when the torrent completed", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "content_path", - description: "Absolute path of torrent content (root path for multifile torrents, absolute file path for singlefile torrents)", - return_type: String( - TypeInfo { - name: "content_path", - is_optional: false, - is_list: false, - description: Some( - "Absolute path of torrent content (root path for multifile torrents, absolute file path for singlefile torrents)", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "dl_limit", - description: "Torrent download speed limit (bytes/s). -1 if ulimited.", - return_type: Number( - TypeInfo { - name: "dl_limit", - is_optional: false, - is_list: false, - description: Some( - "Torrent download speed limit (bytes/s). -1 if ulimited.", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "dlspeed", - description: "Torrent download speed (bytes/s)", - return_type: Number( - TypeInfo { - name: "dlspeed", - is_optional: false, - is_list: false, - description: Some( - "Torrent download speed (bytes/s)", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "downloaded", - description: "Amount of data downloaded", - return_type: Number( - TypeInfo { - name: "downloaded", - is_optional: false, - is_list: false, - description: Some( - "Amount of data downloaded", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "downloaded_session", - description: "Amount of data downloaded this session", - return_type: Number( - TypeInfo { - name: "downloaded_session", - is_optional: false, - is_list: false, - description: Some( - "Amount of data downloaded this session", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "eta", - description: "Torrent ETA (seconds)", - return_type: Number( - TypeInfo { - name: "eta", - is_optional: false, - is_list: false, - description: Some( - "Torrent ETA (seconds)", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "f_l_piece_prio", - description: "True if first last piece are prioritized", - return_type: Bool( - TypeInfo { - name: "f_l_piece_prio", - is_optional: false, - is_list: false, - description: Some( - "True if first last piece are prioritized", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "force_start", - description: "True if force start is enabled for this torrent", - return_type: Bool( - TypeInfo { - name: "force_start", - is_optional: false, - is_list: false, - description: Some( - "True if force start is enabled for this torrent", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "hash", - description: "Torrent hash", - return_type: String( - TypeInfo { - name: "hash", - is_optional: false, - is_list: false, - description: Some( - "Torrent hash", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "last_activity", - description: "Last time (Unix Epoch) when a chunk was downloaded/uploaded", - return_type: Number( - TypeInfo { - name: "last_activity", - is_optional: false, - is_list: false, - description: Some( - "Last time (Unix Epoch) when a chunk was downloaded/uploaded", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "magnet_uri", - description: "Magnet URI corresponding to this torrent", - return_type: String( - TypeInfo { - name: "magnet_uri", - is_optional: false, - is_list: false, - description: Some( - "Magnet URI corresponding to this torrent", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "max_ratio", - description: "Maximum share ratio until torrent is stopped from seeding/uploading", - return_type: Float( - TypeInfo { - name: "max_ratio", - is_optional: false, - is_list: false, - description: Some( - "Maximum share ratio until torrent is stopped from seeding/uploading", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "max_seeding_time", - description: "Maximum seeding time (seconds) until torrent is stopped from seeding", - return_type: Number( - TypeInfo { - name: "max_seeding_time", - is_optional: false, - is_list: false, - description: Some( - "Maximum seeding time (seconds) until torrent is stopped from seeding", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "name", - description: "Torrent name", - return_type: String( - TypeInfo { - name: "name", - is_optional: false, - is_list: false, - description: Some( - "Torrent name", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "num_complete", - description: "Number of seeds in the swarm", - return_type: Number( - TypeInfo { - name: "num_complete", - is_optional: false, - is_list: false, - description: Some( - "Number of seeds in the swarm", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "num_incomplete", - description: "Number of leechers in the swarm", - return_type: Number( - TypeInfo { - name: "num_incomplete", - is_optional: false, - is_list: false, - description: Some( - "Number of leechers in the swarm", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "num_leechs", - description: "Number of leechers connected to", - return_type: Number( - TypeInfo { - name: "num_leechs", - is_optional: false, - is_list: false, - description: Some( - "Number of leechers connected to", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "num_seeds", - description: "Number of seeds connected to", - return_type: Number( - TypeInfo { - name: "num_seeds", - is_optional: false, - is_list: false, - description: Some( - "Number of seeds connected to", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "priority", - description: "Torrent priority. Returns -1 if queuing is disabled or torrent is in seed mode", - return_type: Number( - TypeInfo { - name: "priority", - is_optional: false, - is_list: false, - description: Some( - "Torrent priority. Returns -1 if queuing is disabled or torrent is in seed mode", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "progress", - description: "Torrent progress (percentage/100)", - return_type: Float( - TypeInfo { - name: "progress", - is_optional: false, - is_list: false, - description: Some( - "Torrent progress (percentage/100)", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "ratio", - description: "Torrent share ratio. Max ratio value: 9999.", - return_type: Float( - TypeInfo { - name: "ratio", - is_optional: false, - is_list: false, - description: Some( - "Torrent share ratio. Max ratio value: 9999.", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "ratio_limit", - description: "TODO (what is different from max_ratio?)", - return_type: Float( - TypeInfo { - name: "ratio_limit", - is_optional: false, - is_list: false, - description: Some( - "TODO (what is different from max_ratio?)", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "save_path", - description: "Path where this torrent's data is stored", - return_type: String( - TypeInfo { - name: "save_path", - is_optional: false, - is_list: false, - description: Some( - "Path where this torrent's data is stored", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "seeding_time", - description: "Torrent elapsed time while complete (seconds)", - return_type: Number( - TypeInfo { - name: "seeding_time", - is_optional: false, - is_list: false, - description: Some( - "Torrent elapsed time while complete (seconds)", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "seeding_time_limit", - description: "TODO (what is different from max_seeding_time?) seeding_time_limit is a per torrent setting, when Automatic Torrent Management is disabled, furthermore then max_seeding_time is set to seeding_time_limit for this torrent. If Automatic Torrent Management is enabled, the value is -2. And if max_seeding_time is unset it have a default value -1.", - return_type: Number( - TypeInfo { - name: "seeding_time_limit", - is_optional: false, - is_list: false, - description: Some( - "TODO (what is different from max_seeding_time?) seeding_time_limit is a per torrent setting, when Automatic Torrent Management is disabled, furthermore then max_seeding_time is set to seeding_time_limit for this torrent. If Automatic Torrent Management is enabled, the value is -2. And if max_seeding_time is unset it have a default value -1.", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "seen_complete", - description: "Time (Unix Epoch) when this torrent was last seen complete", - return_type: Number( - TypeInfo { - name: "seen_complete", - is_optional: false, - is_list: false, - description: Some( - "Time (Unix Epoch) when this torrent was last seen complete", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "seq_dl", - description: "True if sequential download is enabled", - return_type: Bool( - TypeInfo { - name: "seq_dl", - is_optional: false, - is_list: false, - description: Some( - "True if sequential download is enabled", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "size", - description: "Total size (bytes) of files selected for download", - return_type: Number( - TypeInfo { - name: "size", - is_optional: false, - is_list: false, - description: Some( - "Total size (bytes) of files selected for download", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "state", - description: "Torrent state. See table here below for the possible values", - return_type: String( - TypeInfo { - name: "state", - is_optional: false, - is_list: false, - description: Some( - "Torrent state. See table here below for the possible values", - ), - type_description: Some( - TypeDescription { - values: [ - TypeDescriptions { - value: "error", - description: "Some error occurred, applies to paused torrents", - }, - TypeDescriptions { - value: "missingFiles", - description: "Torrent data files is missing", - }, - TypeDescriptions { - value: "uploading", - description: "Torrent is being seeded and data is being transferred", - }, - TypeDescriptions { - value: "pausedUP", - description: "Torrent is paused and has finished downloading", - }, - TypeDescriptions { - value: "queuedUP", - description: "Queuing is enabled and torrent is queued for upload", - }, - TypeDescriptions { - value: "stalledUP", - description: "Torrent is being seeded, but no connection were made", - }, - TypeDescriptions { - value: "checkingUP", - description: "Torrent has finished downloading and is being checked", - }, - TypeDescriptions { - value: "forcedUP", - description: "Torrent is forced to uploading and ignore queue limit", - }, - TypeDescriptions { - value: "allocating", - description: "Torrent is allocating disk space for download", - }, - TypeDescriptions { - value: "downloading", - description: "Torrent is being downloaded and data is being transferred", - }, - TypeDescriptions { - value: "metaDL", - description: "Torrent has just started downloading and is fetching metadata", - }, - TypeDescriptions { - value: "pausedDL", - description: "Torrent is paused and has NOT finished downloading", - }, - TypeDescriptions { - value: "queuedDL", - description: "Queuing is enabled and torrent is queued for download", - }, - TypeDescriptions { - value: "stalledDL", - description: "Torrent is being downloaded, but no connection were made", - }, - TypeDescriptions { - value: "checkingDL", - description: "Same as checkingUP, but torrent has NOT finished downloading", - }, - TypeDescriptions { - value: "forcedDL", - description: "Torrent is forced to downloading to ignore queue limit", - }, - TypeDescriptions { - value: "checkingResumeData", - description: "Checking resume data on qBt startup", - }, - TypeDescriptions { - value: "moving", - description: "Torrent is moving to another location", - }, - TypeDescriptions { - value: "unknown", - description: "Unknown status", - }, - ], - }, - ), - }, - ), - }, - ReturnTypeParameter { - name: "super_seeding", - description: "True if super seeding is enabled", - return_type: Bool( - TypeInfo { - name: "super_seeding", - is_optional: false, - is_list: false, - description: Some( - "True if super seeding is enabled", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "tags", - description: "Comma-concatenated tag list of the torrent", - return_type: String( - TypeInfo { - name: "tags", - is_optional: false, - is_list: false, - description: Some( - "Comma-concatenated tag list of the torrent", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "time_active", - description: "Total active time (seconds)", - return_type: Number( - TypeInfo { - name: "time_active", - is_optional: false, - is_list: false, - description: Some( - "Total active time (seconds)", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "total_size", - description: "Total size (bytes) of all file in this torrent (including unselected ones)", - return_type: Number( - TypeInfo { - name: "total_size", - is_optional: false, - is_list: false, - description: Some( - "Total size (bytes) of all file in this torrent (including unselected ones)", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "tracker", - description: "The first tracker with working status. Returns empty string if no tracker is working.", - return_type: String( - TypeInfo { - name: "tracker", - is_optional: false, - is_list: false, - description: Some( - "The first tracker with working status. Returns empty string if no tracker is working.", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "up_limit", - description: "Torrent upload speed limit (bytes/s). -1 if ulimited.", - return_type: Number( - TypeInfo { - name: "up_limit", - is_optional: false, - is_list: false, - description: Some( - "Torrent upload speed limit (bytes/s). -1 if ulimited.", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "uploaded", - description: "Amount of data uploaded", - return_type: Number( - TypeInfo { - name: "uploaded", - is_optional: false, - is_list: false, - description: Some( - "Amount of data uploaded", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "uploaded_session", - description: "Amount of data uploaded this session", - return_type: Number( - TypeInfo { - name: "uploaded_session", - is_optional: false, - is_list: false, - description: Some( - "Amount of data uploaded this session", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "upspeed", - description: "Torrent upload speed (bytes/s)", - return_type: Number( - TypeInfo { - name: "upspeed", - is_optional: false, - is_list: false, - description: Some( - "Torrent upload speed (bytes/s)", - ), - type_description: None, - }, - ), - }, - ], - }, - ), url: "info", + types: CompositeTypes { + composite_types: [ + Parameters( + TypeWithoutName { + types: [ + String( + TypeInfo { + name: "filter", + is_optional: true, + is_list: false, + description: Some( + "Filter torrent list by state. Allowed state filters: all, downloading, seeding, completed, paused, active, inactive, resumed, stalled, stalled_uploading, stalled_downloading, errored", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "category", + is_optional: true, + is_list: false, + description: Some( + "Get torrents with the given category (empty string means \"without category\"; no \"category\" parameter means \"any category\" <- broken until [#11748](https://github.com/qbittorrent/qBittorrent/issues/11748) is resolved). Remember to URL-encode the category name. For example, My category becomes My%20category", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "tag", + is_optional: true, + is_list: false, + description: Some( + "Get torrents with the given tag (empty string means \"without tag\"; no \"tag\" parameter means \"any tag\". Remember to URL-encode the category name. For example, My tag becomes My%20tag", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "sort", + is_optional: true, + is_list: false, + description: Some( + "Sort torrents by given key. They can be sorted using any field of the response's JSON array (which are documented below) as the sort key.", + ), + type_description: None, + }, + ), + Bool( + TypeInfo { + name: "reverse", + is_optional: true, + is_list: false, + description: Some( + "Enable reverse sorting. Defaults to false", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "limit", + is_optional: true, + is_list: false, + description: Some( + "Limit the number of torrents returned", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "offset", + is_optional: true, + is_list: false, + description: Some( + "Set offset (if less than 0, offset from end)", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "hashes", + is_optional: true, + is_list: false, + description: Some( + "Filter by hashes. Can contain multiple hashes separated by \\", + ), + type_description: None, + }, + ), + ], + }, + ), + Enum( + Enum { + name: "State", + values: [ + EnumValue { + description: Some( + "Some error occurred, applies to paused torrents", + ), + value: "Error", + original_value: "error", + }, + EnumValue { + description: Some( + "Torrent data files is missing", + ), + value: "MissingFiles", + original_value: "missingFiles", + }, + EnumValue { + description: Some( + "Torrent is being seeded and data is being transferred", + ), + value: "Uploading", + original_value: "uploading", + }, + EnumValue { + description: Some( + "Torrent is paused and has finished downloading", + ), + value: "PausedUP", + original_value: "pausedUP", + }, + EnumValue { + description: Some( + "Queuing is enabled and torrent is queued for upload", + ), + value: "QueuedUP", + original_value: "queuedUP", + }, + EnumValue { + description: Some( + "Torrent is being seeded, but no connection were made", + ), + value: "StalledUP", + original_value: "stalledUP", + }, + EnumValue { + description: Some( + "Torrent has finished downloading and is being checked", + ), + value: "CheckingUP", + original_value: "checkingUP", + }, + EnumValue { + description: Some( + "Torrent is forced to uploading and ignore queue limit", + ), + value: "ForcedUP", + original_value: "forcedUP", + }, + EnumValue { + description: Some( + "Torrent is allocating disk space for download", + ), + value: "Allocating", + original_value: "allocating", + }, + EnumValue { + description: Some( + "Torrent is being downloaded and data is being transferred", + ), + value: "Downloading", + original_value: "downloading", + }, + EnumValue { + description: Some( + "Torrent has just started downloading and is fetching metadata", + ), + value: "MetaDL", + original_value: "metaDL", + }, + EnumValue { + description: Some( + "Torrent is paused and has NOT finished downloading", + ), + value: "PausedDL", + original_value: "pausedDL", + }, + EnumValue { + description: Some( + "Queuing is enabled and torrent is queued for download", + ), + value: "QueuedDL", + original_value: "queuedDL", + }, + EnumValue { + description: Some( + "Torrent is being downloaded, but no connection were made", + ), + value: "StalledDL", + original_value: "stalledDL", + }, + EnumValue { + description: Some( + "Same as checkingUP, but torrent has NOT finished downloading", + ), + value: "CheckingDL", + original_value: "checkingDL", + }, + EnumValue { + description: Some( + "Torrent is forced to downloading to ignore queue limit", + ), + value: "ForcedDL", + original_value: "forcedDL", + }, + EnumValue { + description: Some( + "Checking resume data on qBt startup", + ), + value: "CheckingResumeData", + original_value: "checkingResumeData", + }, + EnumValue { + description: Some( + "Torrent is moving to another location", + ), + value: "Moving", + original_value: "moving", + }, + EnumValue { + description: Some( + "Unknown status", + ), + value: "Unknown", + original_value: "unknown", + }, + ], + }, + ), + Response( + TypeWithoutName { + types: [ + Number( + TypeInfo { + name: "added_on", + is_optional: false, + is_list: false, + description: Some( + "Time (Unix Epoch) when the torrent was added to the client", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "amount_left", + is_optional: false, + is_list: false, + description: Some( + "Amount of data left to download (bytes)", + ), + type_description: None, + }, + ), + Bool( + TypeInfo { + name: "auto_tmm", + is_optional: false, + is_list: false, + description: Some( + "Whether this torrent is managed by Automatic Torrent Management", + ), + type_description: None, + }, + ), + Float( + TypeInfo { + name: "availability", + is_optional: false, + is_list: false, + description: Some( + "Percentage of file pieces currently available", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "category", + is_optional: false, + is_list: false, + description: Some( + "Category of the torrent", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "completed", + is_optional: false, + is_list: false, + description: Some( + "Amount of transfer data completed (bytes)", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "completion_on", + is_optional: false, + is_list: false, + description: Some( + "Time (Unix Epoch) when the torrent completed", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "content_path", + is_optional: false, + is_list: false, + description: Some( + "Absolute path of torrent content (root path for multifile torrents, absolute file path for singlefile torrents)", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "dl_limit", + is_optional: false, + is_list: false, + description: Some( + "Torrent download speed limit (bytes/s). -1 if ulimited.", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "dlspeed", + is_optional: false, + is_list: false, + description: Some( + "Torrent download speed (bytes/s)", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "downloaded", + is_optional: false, + is_list: false, + description: Some( + "Amount of data downloaded", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "downloaded_session", + is_optional: false, + is_list: false, + description: Some( + "Amount of data downloaded this session", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "eta", + is_optional: false, + is_list: false, + description: Some( + "Torrent ETA (seconds)", + ), + type_description: None, + }, + ), + Bool( + TypeInfo { + name: "f_l_piece_prio", + is_optional: false, + is_list: false, + description: Some( + "True if first last piece are prioritized", + ), + type_description: None, + }, + ), + Bool( + TypeInfo { + name: "force_start", + is_optional: false, + is_list: false, + description: Some( + "True if force start is enabled for this torrent", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "hash", + is_optional: false, + is_list: false, + description: Some( + "Torrent hash", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "last_activity", + is_optional: false, + is_list: false, + description: Some( + "Last time (Unix Epoch) when a chunk was downloaded/uploaded", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "magnet_uri", + is_optional: false, + is_list: false, + description: Some( + "Magnet URI corresponding to this torrent", + ), + type_description: None, + }, + ), + Float( + TypeInfo { + name: "max_ratio", + is_optional: false, + is_list: false, + description: Some( + "Maximum share ratio until torrent is stopped from seeding/uploading", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "max_seeding_time", + is_optional: false, + is_list: false, + description: Some( + "Maximum seeding time (seconds) until torrent is stopped from seeding", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "name", + is_optional: false, + is_list: false, + description: Some( + "Torrent name", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "num_complete", + is_optional: false, + is_list: false, + description: Some( + "Number of seeds in the swarm", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "num_incomplete", + is_optional: false, + is_list: false, + description: Some( + "Number of leechers in the swarm", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "num_leechs", + is_optional: false, + is_list: false, + description: Some( + "Number of leechers connected to", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "num_seeds", + is_optional: false, + is_list: false, + description: Some( + "Number of seeds connected to", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "priority", + is_optional: false, + is_list: false, + description: Some( + "Torrent priority. Returns -1 if queuing is disabled or torrent is in seed mode", + ), + type_description: None, + }, + ), + Float( + TypeInfo { + name: "progress", + is_optional: false, + is_list: false, + description: Some( + "Torrent progress (percentage/100)", + ), + type_description: None, + }, + ), + Float( + TypeInfo { + name: "ratio", + is_optional: false, + is_list: false, + description: Some( + "Torrent share ratio. Max ratio value: 9999.", + ), + type_description: None, + }, + ), + Float( + TypeInfo { + name: "ratio_limit", + is_optional: false, + is_list: false, + description: Some( + "TODO (what is different from max_ratio?)", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "save_path", + is_optional: false, + is_list: false, + description: Some( + "Path where this torrent's data is stored", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "seeding_time", + is_optional: false, + is_list: false, + description: Some( + "Torrent elapsed time while complete (seconds)", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "seeding_time_limit", + is_optional: false, + is_list: false, + description: Some( + "TODO (what is different from max_seeding_time?) seeding_time_limit is a per torrent setting, when Automatic Torrent Management is disabled, furthermore then max_seeding_time is set to seeding_time_limit for this torrent. If Automatic Torrent Management is enabled, the value is -2. And if max_seeding_time is unset it have a default value -1.", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "seen_complete", + is_optional: false, + is_list: false, + description: Some( + "Time (Unix Epoch) when this torrent was last seen complete", + ), + type_description: None, + }, + ), + Bool( + TypeInfo { + name: "seq_dl", + is_optional: false, + is_list: false, + description: Some( + "True if sequential download is enabled", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "size", + is_optional: false, + is_list: false, + description: Some( + "Total size (bytes) of files selected for download", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "state", + is_optional: false, + is_list: false, + description: Some( + "Torrent state. See table here below for the possible values", + ), + type_description: None, + }, + ), + Bool( + TypeInfo { + name: "super_seeding", + is_optional: false, + is_list: false, + description: Some( + "True if super seeding is enabled", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "tags", + is_optional: false, + is_list: false, + description: Some( + "Comma-concatenated tag list of the torrent", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "time_active", + is_optional: false, + is_list: false, + description: Some( + "Total active time (seconds)", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "total_size", + is_optional: false, + is_list: false, + description: Some( + "Total size (bytes) of all file in this torrent (including unselected ones)", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "tracker", + is_optional: false, + is_list: false, + description: Some( + "The first tracker with working status. Returns empty string if no tracker is working.", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "up_limit", + is_optional: false, + is_list: false, + description: Some( + "Torrent upload speed limit (bytes/s). -1 if ulimited.", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "uploaded", + is_optional: false, + is_list: false, + description: Some( + "Amount of data uploaded", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "uploaded_session", + is_optional: false, + is_list: false, + description: Some( + "Amount of data uploaded this session", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "upspeed", + is_optional: false, + is_list: false, + description: Some( + "Torrent upload speed (bytes/s)", + ), + type_description: None, + }, + ), + ], + }, + ), + ], + }, }, ApiMethod { name: "properties", description: Some( "The response is:\n\n- empty, if the torrent hash is invalid\n- otherwise, a JSON object with the following fields\n\n\nNB: `-1` is returned if the type of the property is integer but its value is not known.\n\nExample:\n\n```JSON\n{\n \"addition_date\":1438429165,\n \"comment\":\"\\\"Debian CD from cdimage.debian.org\\\"\",\n \"completion_date\":1438429234,\n \"created_by\":\"\",\n \"creation_date\":1433605214,\n \"dl_limit\":-1,\n \"dl_speed\":0,\n \"dl_speed_avg\":9736015,\n \"eta\":8640000,\n \"last_seen\":1438430354,\n \"nb_connections\":3,\n \"nb_connections_limit\":250,\n \"peers\":1,\n \"peers_total\":89,\n \"piece_size\":524288,\n \"pieces_have\":1254,\n \"pieces_num\":1254,\n \"reannounce\":672,\n \"save_path\":\"/Downloads/debian-8.1.0-amd64-CD-1.iso\",\n \"seeding_time\":1128,\n \"seeds\":1,\n \"seeds_total\":254,\n \"share_ratio\":0.00072121022562178299,\n \"time_elapsed\":1197,\n \"total_downloaded\":681521119,\n \"total_downloaded_session\":681521119,\n \"total_size\":657457152,\n \"total_uploaded\":491520,\n \"total_uploaded_session\":491520,\n \"total_wasted\":23481724,\n \"up_limit\":-1,\n \"up_speed\":0,\n \"up_speed_avg\":410\n}\n```", ), - parameters: Some( - ApiParameters { - mandatory: [ - String( - TypeInfo { - name: "hash", - is_optional: false, - is_list: false, - description: Some( - "The hash of the torrent you want to get the generic properties of", - ), - type_description: None, - }, - ), - ], - optional: [], - }, - ), - return_type: None, url: "properties", + types: CompositeTypes { + composite_types: [ + Parameters( + TypeWithoutName { + types: [ + String( + TypeInfo { + name: "hash", + is_optional: false, + is_list: false, + description: Some( + "The hash of the torrent you want to get the generic properties of", + ), + type_description: None, + }, + ), + ], + }, + ), + ], + }, }, ApiMethod { name: "trackers", description: Some( "The response is a JSON array, where each element contains info about one tracker, with the following fields\n\n\nPossible values of `status`:\n\n\nExample:\n\n```JSON\n[\n {\n \"msg\":\"\",\n \"num_peers\":100,\n \"status\":2,\n \"url\":\"http://bttracker.debian.org:6969/announce\"\n },\n {\n another_tracker_info\n }\n]\n```", ), - parameters: Some( - ApiParameters { - mandatory: [ - String( - TypeInfo { - name: "hash", - is_optional: false, - is_list: false, - description: Some( - "The hash of the torrent you want to get the trackers of", - ), - type_description: None, - }, - ), - ], - optional: [], - }, - ), - return_type: Some( - ReturnType { - is_list: true, - parameters: [ - ReturnTypeParameter { - name: "url", - description: "Tracker url", - return_type: String( - TypeInfo { - name: "url", - is_optional: false, - is_list: false, - description: Some( - "Tracker url", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "status", - description: "Tracker status. See the table below for possible values", - return_type: Number( - TypeInfo { - name: "status", - is_optional: false, - is_list: false, - description: Some( - "Tracker status. See the table below for possible values", - ), - type_description: Some( - TypeDescription { - values: [ - TypeDescriptions { - value: "0", - description: "Tracker is disabled (used for DHT, PeX, and LSD)", - }, - TypeDescriptions { - value: "1", - description: "Tracker has not been contacted yet", - }, - TypeDescriptions { - value: "2", - description: "Tracker has been contacted and is working", - }, - TypeDescriptions { - value: "3", - description: "Tracker is updating", - }, - TypeDescriptions { - value: "4", - description: "Tracker has been contacted, but it is not working (or doesn't send proper replies)", - }, - ], - }, - ), - }, - ), - }, - ReturnTypeParameter { - name: "tier", - description: "Tracker priority tier. Lower tier trackers are tried before higher tiers. Tier numbers are valid when >= 0, < 0 is used as placeholder when tier does not exist for special entries (such as DHT).", - return_type: Number( - TypeInfo { - name: "tier", - is_optional: false, - is_list: false, - description: Some( - "Tracker priority tier. Lower tier trackers are tried before higher tiers. Tier numbers are valid when >= 0, < 0 is used as placeholder when tier does not exist for special entries (such as DHT).", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "num_peers", - description: "Number of peers for current torrent, as reported by the tracker", - return_type: Number( - TypeInfo { - name: "num_peers", - is_optional: false, - is_list: false, - description: Some( - "Number of peers for current torrent, as reported by the tracker", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "num_seeds", - description: "Number of seeds for current torrent, asreported by the tracker", - return_type: Number( - TypeInfo { - name: "num_seeds", - is_optional: false, - is_list: false, - description: Some( - "Number of seeds for current torrent, asreported by the tracker", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "num_leeches", - description: "Number of leeches for current torrent, as reported by the tracker", - return_type: Number( - TypeInfo { - name: "num_leeches", - is_optional: false, - is_list: false, - description: Some( - "Number of leeches for current torrent, as reported by the tracker", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "num_downloaded", - description: "Number of completed downlods for current torrent, as reported by the tracker", - return_type: Number( - TypeInfo { - name: "num_downloaded", - is_optional: false, - is_list: false, - description: Some( - "Number of completed downlods for current torrent, as reported by the tracker", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "msg", - description: "Tracker message (there is no way of knowing what this message is - it's up to tracker admins)", - return_type: String( - TypeInfo { - name: "msg", - is_optional: false, - is_list: false, - description: Some( - "Tracker message (there is no way of knowing what this message is - it's up to tracker admins)", - ), - type_description: None, - }, - ), - }, - ], - }, - ), url: "trackers", + types: CompositeTypes { + composite_types: [ + Parameters( + TypeWithoutName { + types: [ + String( + TypeInfo { + name: "hash", + is_optional: false, + is_list: false, + description: Some( + "The hash of the torrent you want to get the trackers of", + ), + type_description: None, + }, + ), + ], + }, + ), + Enum( + Enum { + name: "Status", + values: [ + EnumValue { + description: Some( + "Tracker is disabled (used for DHT, PeX, and LSD)", + ), + value: "TrackerIsDisabled", + original_value: "0", + }, + EnumValue { + description: Some( + "Tracker has not been contacted yet", + ), + value: "TrackerHasNotBeenContactedYet", + original_value: "1", + }, + EnumValue { + description: Some( + "Tracker has been contacted and is working", + ), + value: "TrackerHasBeenContactedAndIsWorking", + original_value: "2", + }, + EnumValue { + description: Some( + "Tracker is updating", + ), + value: "TrackerIsUpdating", + original_value: "3", + }, + EnumValue { + description: Some( + "Tracker has been contacted, but it is not working (or doesn't send proper replies)", + ), + value: "TrackerHasBeenContactedButItIsNotWorking", + original_value: "4", + }, + ], + }, + ), + Response( + TypeWithoutName { + types: [ + String( + TypeInfo { + name: "url", + is_optional: false, + is_list: false, + description: Some( + "Tracker url", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "status", + is_optional: false, + is_list: false, + description: Some( + "Tracker status. See the table below for possible values", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "tier", + is_optional: false, + is_list: false, + description: Some( + "Tracker priority tier. Lower tier trackers are tried before higher tiers. Tier numbers are valid when >= 0, < 0 is used as placeholder when tier does not exist for special entries (such as DHT).", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "num_peers", + is_optional: false, + is_list: false, + description: Some( + "Number of peers for current torrent, as reported by the tracker", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "num_seeds", + is_optional: false, + is_list: false, + description: Some( + "Number of seeds for current torrent, asreported by the tracker", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "num_leeches", + is_optional: false, + is_list: false, + description: Some( + "Number of leeches for current torrent, as reported by the tracker", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "num_downloaded", + is_optional: false, + is_list: false, + description: Some( + "Number of completed downlods for current torrent, as reported by the tracker", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "msg", + is_optional: false, + is_list: false, + description: Some( + "Tracker message (there is no way of knowing what this message is - it's up to tracker admins)", + ), + type_description: None, + }, + ), + ], + }, + ), + ], + }, }, ApiMethod { name: "webseeds", description: Some( "The response is a JSON array, where each element is information about one webseed, with the following fields\n\n\nExample:\n\n```JSON\n[\n {\n \"url\":\"http://some_url/\"\n },\n {\n \"url\":\"http://some_other_url/\"\n }\n]\n```", ), - parameters: Some( - ApiParameters { - mandatory: [ - String( - TypeInfo { - name: "hash", - is_optional: false, - is_list: false, - description: Some( - "The hash of the torrent you want to get the webseeds of", - ), - type_description: None, - }, - ), - ], - optional: [], - }, - ), - return_type: Some( - ReturnType { - is_list: true, - parameters: [ - ReturnTypeParameter { - name: "url", - description: "URL of the web seed", - return_type: String( - TypeInfo { - name: "url", - is_optional: false, - is_list: false, - description: Some( - "URL of the web seed", - ), - type_description: None, - }, - ), - }, - ], - }, - ), url: "webseeds", + types: CompositeTypes { + composite_types: [ + Parameters( + TypeWithoutName { + types: [ + String( + TypeInfo { + name: "hash", + is_optional: false, + is_list: false, + description: Some( + "The hash of the torrent you want to get the webseeds of", + ), + type_description: None, + }, + ), + ], + }, + ), + Response( + TypeWithoutName { + types: [ + String( + TypeInfo { + name: "url", + is_optional: false, + is_list: false, + description: Some( + "URL of the web seed", + ), + type_description: None, + }, + ), + ], + }, + ), + ], + }, }, ApiMethod { name: "files", description: Some( "The response is:\n\n- empty, if the torrent hash is invalid\n- otherwise, a JSON array, where each element contains info about one file, with the following fields\n\n\nPossible values of `priority`:\n\n\nExample:\n\n```JSON\n\n[\n {\n \"index\":0,\n \"is_seed\":false,\n \"name\":\"debian-8.1.0-amd64-CD-1.iso\",\n \"piece_range\":[0,1253],\n \"priority\":1,\n \"progress\":0,\n \"size\":657457152,\n \"availability\":0.5,\n }\n]\n```", ), - parameters: Some( - ApiParameters { - mandatory: [ - String( - TypeInfo { - name: "hash", - is_optional: false, - is_list: false, - description: Some( - "The hash of the torrent you want to get the contents of", - ), - type_description: None, - }, - ), - ], - optional: [ - String( - TypeInfo { - name: "indexes", - is_optional: true, - is_list: false, - description: Some( - "The indexes of the files you want to retrieve. indexes can contain multiple values separated by \\", - ), - type_description: None, - }, - ), - ], - }, - ), - return_type: None, url: "files", + types: CompositeTypes { + composite_types: [ + Parameters( + TypeWithoutName { + types: [ + String( + TypeInfo { + name: "hash", + is_optional: false, + is_list: false, + description: Some( + "The hash of the torrent you want to get the contents of", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "indexes", + is_optional: true, + is_list: false, + description: Some( + "The indexes of the files you want to retrieve. indexes can contain multiple values separated by \\", + ), + type_description: None, + }, + ), + ], + }, + ), + Enum( + Enum { + name: "Priority", + values: [ + EnumValue { + description: Some( + "Do not download", + ), + value: "DoNotDownload", + original_value: "0", + }, + EnumValue { + description: Some( + "Normal priority", + ), + value: "NormalPriority", + original_value: "1", + }, + EnumValue { + description: Some( + "High priority", + ), + value: "HighPriority", + original_value: "6", + }, + EnumValue { + description: Some( + "Maximal priority", + ), + value: "MaximalPriority", + original_value: "7", + }, + ], + }, + ), + ], + }, }, ApiMethod { name: "pieceStates", description: Some( "The response is:\n\n- empty, if the torrent hash is invalid\n- otherwise, an array of states (integers) of all pieces (in order) of a specific torrent.\n\nValue meanings are defined as below:\n\n\nExample:\n\n```JSON\n[0,0,2,1,0,0,2,1]\n```", ), - parameters: Some( - ApiParameters { - mandatory: [ - String( - TypeInfo { - name: "hash", - is_optional: false, - is_list: false, - description: Some( - "The hash of the torrent you want to get the pieces' states of", - ), - type_description: None, - }, - ), - ], - optional: [], - }, - ), - return_type: None, url: "pieceStates", + types: CompositeTypes { + composite_types: [ + Parameters( + TypeWithoutName { + types: [ + String( + TypeInfo { + name: "hash", + is_optional: false, + is_list: false, + description: Some( + "The hash of the torrent you want to get the pieces' states of", + ), + type_description: None, + }, + ), + ], + }, + ), + ], + }, }, ApiMethod { name: "pieceHashes", description: Some( "The response is:\n\n- empty, if the torrent hash is invalid\n- otherwise, an array of hashes (strings) of all pieces (in order) of a specific torrent.\n\nExample:\n\n```JSON\n[\"54eddd830a5b58480a6143d616a97e3a6c23c439\",\"f8a99d225aa4241db100f88407fc3bdaead583ab\",\"928fb615b9bd4dd8f9e9022552c8f8f37ef76f58\"]\n```", ), - parameters: Some( - ApiParameters { - mandatory: [ - String( - TypeInfo { - name: "hash", - is_optional: false, - is_list: false, - description: Some( - "The hash of the torrent you want to get the pieces' hashes of", - ), - type_description: None, - }, - ), - ], - optional: [], - }, - ), - return_type: None, url: "pieceHashes", + types: CompositeTypes { + composite_types: [ + Parameters( + TypeWithoutName { + types: [ + String( + TypeInfo { + name: "hash", + is_optional: false, + is_list: false, + description: Some( + "The hash of the torrent you want to get the pieces' hashes of", + ), + type_description: None, + }, + ), + ], + }, + ), + ], + }, }, ApiMethod { name: "pause", description: None, - parameters: Some( - ApiParameters { - mandatory: [ - String( - TypeInfo { - name: "hashes", - is_optional: false, - is_list: false, - description: Some( - "The hashes of the torrents you want to pause. hashes can contain multiple hashes separated by \\", - ), - type_description: None, - }, - ), - ], - optional: [], - }, - ), - return_type: None, url: "pause", + types: CompositeTypes { + composite_types: [ + Parameters( + TypeWithoutName { + types: [ + String( + TypeInfo { + name: "hashes", + is_optional: false, + is_list: false, + description: Some( + "The hashes of the torrents you want to pause. hashes can contain multiple hashes separated by \\", + ), + type_description: None, + }, + ), + ], + }, + ), + ], + }, }, ApiMethod { name: "resume", description: None, - parameters: Some( - ApiParameters { - mandatory: [ - String( - TypeInfo { - name: "hashes", - is_optional: false, - is_list: false, - description: Some( - "The hashes of the torrents you want to resume. hashes can contain multiple hashes separated by \\", - ), - type_description: None, - }, - ), - ], - optional: [], - }, - ), - return_type: None, url: "resume", + types: CompositeTypes { + composite_types: [ + Parameters( + TypeWithoutName { + types: [ + String( + TypeInfo { + name: "hashes", + is_optional: false, + is_list: false, + description: Some( + "The hashes of the torrents you want to resume. hashes can contain multiple hashes separated by \\", + ), + type_description: None, + }, + ), + ], + }, + ), + ], + }, }, ApiMethod { name: "delete", description: None, - parameters: Some( - ApiParameters { - mandatory: [ - String( - TypeInfo { - name: "hashes", - is_optional: false, - is_list: false, - description: Some( - "The hashes of the torrents you want to delete. hashes can contain multiple hashes separated by \\", - ), - type_description: None, - }, - ), - ], - optional: [], - }, - ), - return_type: None, url: "delete", + types: CompositeTypes { + composite_types: [ + Parameters( + TypeWithoutName { + types: [ + String( + TypeInfo { + name: "hashes", + is_optional: false, + is_list: false, + description: Some( + "The hashes of the torrents you want to delete. hashes can contain multiple hashes separated by \\", + ), + type_description: None, + }, + ), + Object( + Object { + type_info: TypeInfo { + name: "deleteFiles", + is_optional: false, + is_list: false, + description: None, + type_description: None, + }, + ref_type: "If set to true, the downloaded data will also be deleted, otherwise has no effect.", + }, + ), + ], + }, + ), + ], + }, }, ApiMethod { name: "recheck", description: None, - parameters: Some( - ApiParameters { - mandatory: [ - String( - TypeInfo { - name: "hashes", - is_optional: false, - is_list: false, - description: Some( - "The hashes of the torrents you want to recheck. hashes can contain multiple hashes separated by \\", - ), - type_description: None, - }, - ), - ], - optional: [], - }, - ), - return_type: None, url: "recheck", + types: CompositeTypes { + composite_types: [ + Parameters( + TypeWithoutName { + types: [ + String( + TypeInfo { + name: "hashes", + is_optional: false, + is_list: false, + description: Some( + "The hashes of the torrents you want to recheck. hashes can contain multiple hashes separated by \\", + ), + type_description: None, + }, + ), + ], + }, + ), + ], + }, }, ApiMethod { name: "reannounce", description: None, - parameters: Some( - ApiParameters { - mandatory: [ - String( - TypeInfo { - name: "hashes", - is_optional: false, - is_list: false, - description: Some( - "The hashes of the torrents you want to reannounce. hashes can contain multiple hashes separated by \\", - ), - type_description: None, - }, - ), - ], - optional: [], - }, - ), - return_type: None, url: "reannounce", + types: CompositeTypes { + composite_types: [ + Parameters( + TypeWithoutName { + types: [ + String( + TypeInfo { + name: "hashes", + is_optional: false, + is_list: false, + description: Some( + "The hashes of the torrents you want to reannounce. hashes can contain multiple hashes separated by \\", + ), + type_description: None, + }, + ), + ], + }, + ), + ], + }, }, ApiMethod { name: "add", description: None, - parameters: Some( - ApiParameters { - mandatory: [ - String( - TypeInfo { - name: "urls", - is_optional: false, - is_list: false, - description: Some( - "URLs separated with newlines", - ), - type_description: None, - }, - ), - ], - optional: [ - String( - TypeInfo { - name: "savepath", - is_optional: true, - is_list: false, - description: Some( - "Download folder", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "cookie", - is_optional: true, - is_list: false, - description: Some( - "Cookie sent to download the .torrent file", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "category", - is_optional: true, - is_list: false, - description: Some( - "Category for the torrent", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "tags", - is_optional: true, - is_list: false, - description: Some( - "Tags for the torrent, split by ','", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "skip_checking", - is_optional: true, - is_list: false, - description: Some( - "Skip hash checking. Possible values are true, false (default)", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "paused", - is_optional: true, - is_list: false, - description: Some( - "Add torrents in the paused state. Possible values are true, false (default)", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "root_folder", - is_optional: true, - is_list: false, - description: Some( - "Create the root folder. Possible values are true, false, unset (default)", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "rename", - is_optional: true, - is_list: false, - description: Some( - "Rename torrent", - ), - type_description: None, - }, - ), - Number( - TypeInfo { - name: "upLimit", - is_optional: true, - is_list: false, - description: Some( - "Set torrent upload speed limit. Unit in bytes/second", - ), - type_description: None, - }, - ), - Number( - TypeInfo { - name: "dlLimit", - is_optional: true, - is_list: false, - description: Some( - "Set torrent download speed limit. Unit in bytes/second", - ), - type_description: None, - }, - ), - Float( - TypeInfo { - name: "ratioLimit", - is_optional: true, - is_list: false, - description: Some( - "Set torrent share ratio limit", - ), - type_description: None, - }, - ), - Number( - TypeInfo { - name: "seedingTimeLimit", - is_optional: true, - is_list: false, - description: Some( - "Set torrent seeding time limit. Unit in seconds", - ), - type_description: None, - }, - ), - Bool( - TypeInfo { - name: "autoTMM", - is_optional: true, - is_list: false, - description: Some( - "Whether Automatic Torrent Management should be used", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "sequentialDownload", - is_optional: true, - is_list: false, - description: Some( - "Enable sequential download. Possible values are true, false (default)", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "firstLastPiecePrio", - is_optional: true, - is_list: false, - description: Some( - "Prioritize download first last piece. Possible values are true, false (default)", - ), - type_description: None, - }, - ), - ], - }, - ), - return_type: None, url: "add", + types: CompositeTypes { + composite_types: [ + Parameters( + TypeWithoutName { + types: [ + String( + TypeInfo { + name: "urls", + is_optional: false, + is_list: false, + description: Some( + "URLs separated with newlines", + ), + type_description: None, + }, + ), + Object( + Object { + type_info: TypeInfo { + name: "torrents", + is_optional: false, + is_list: false, + description: Some( + "Raw data of torrent file. torrents can be presented multiple times.", + ), + type_description: None, + }, + ref_type: "Raw", + }, + ), + String( + TypeInfo { + name: "savepath", + is_optional: true, + is_list: false, + description: Some( + "Download folder", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "cookie", + is_optional: true, + is_list: false, + description: Some( + "Cookie sent to download the .torrent file", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "category", + is_optional: true, + is_list: false, + description: Some( + "Category for the torrent", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "tags", + is_optional: true, + is_list: false, + description: Some( + "Tags for the torrent, split by ','", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "skip_checking", + is_optional: true, + is_list: false, + description: Some( + "Skip hash checking. Possible values are true, false (default)", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "paused", + is_optional: true, + is_list: false, + description: Some( + "Add torrents in the paused state. Possible values are true, false (default)", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "root_folder", + is_optional: true, + is_list: false, + description: Some( + "Create the root folder. Possible values are true, false, unset (default)", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "rename", + is_optional: true, + is_list: false, + description: Some( + "Rename torrent", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "upLimit", + is_optional: true, + is_list: false, + description: Some( + "Set torrent upload speed limit. Unit in bytes/second", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "dlLimit", + is_optional: true, + is_list: false, + description: Some( + "Set torrent download speed limit. Unit in bytes/second", + ), + type_description: None, + }, + ), + Float( + TypeInfo { + name: "ratioLimit", + is_optional: true, + is_list: false, + description: Some( + "Set torrent share ratio limit", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "seedingTimeLimit", + is_optional: true, + is_list: false, + description: Some( + "Set torrent seeding time limit. Unit in seconds", + ), + type_description: None, + }, + ), + Bool( + TypeInfo { + name: "autoTMM", + is_optional: true, + is_list: false, + description: Some( + "Whether Automatic Torrent Management should be used", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "sequentialDownload", + is_optional: true, + is_list: false, + description: Some( + "Enable sequential download. Possible values are true, false (default)", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "firstLastPiecePrio", + is_optional: true, + is_list: false, + description: Some( + "Prioritize download first last piece. Possible values are true, false (default)", + ), + type_description: None, + }, + ), + ], + }, + ), + ], + }, }, ApiMethod { name: "addTrackers", description: None, - parameters: None, - return_type: None, url: "addTrackers", + types: CompositeTypes { + composite_types: [], + }, }, ApiMethod { name: "editTracker", description: None, - parameters: Some( - ApiParameters { - mandatory: [ - String( - TypeInfo { - name: "hash", - is_optional: false, - is_list: false, - description: Some( - "The hash of the torrent", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "origUrl", - is_optional: false, - is_list: false, - description: Some( - "The tracker URL you want to edit", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "newUrl", - is_optional: false, - is_list: false, - description: Some( - "The new URL to replace the origUrl", - ), - type_description: None, - }, - ), - ], - optional: [], - }, - ), - return_type: None, url: "editTracker", + types: CompositeTypes { + composite_types: [ + Parameters( + TypeWithoutName { + types: [ + String( + TypeInfo { + name: "hash", + is_optional: false, + is_list: false, + description: Some( + "The hash of the torrent", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "origUrl", + is_optional: false, + is_list: false, + description: Some( + "The tracker URL you want to edit", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "newUrl", + is_optional: false, + is_list: false, + description: Some( + "The new URL to replace the origUrl", + ), + type_description: None, + }, + ), + ], + }, + ), + ], + }, }, ApiMethod { name: "removeTrackers", description: None, - parameters: Some( - ApiParameters { - mandatory: [ - String( - TypeInfo { - name: "hash", - is_optional: false, - is_list: false, - description: Some( - "The hash of the torrent", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "urls", - is_optional: false, - is_list: false, - description: Some( - "URLs to remove, separated by \\", - ), - type_description: None, - }, - ), - ], - optional: [], - }, - ), - return_type: None, url: "removeTrackers", + types: CompositeTypes { + composite_types: [ + Parameters( + TypeWithoutName { + types: [ + String( + TypeInfo { + name: "hash", + is_optional: false, + is_list: false, + description: Some( + "The hash of the torrent", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "urls", + is_optional: false, + is_list: false, + description: Some( + "URLs to remove, separated by \\", + ), + type_description: None, + }, + ), + ], + }, + ), + ], + }, }, ApiMethod { name: "addPeers", description: None, - parameters: Some( - ApiParameters { - mandatory: [ - String( - TypeInfo { - name: "hashes", - is_optional: false, - is_list: false, - description: Some( - "The hash of the torrent, or multiple hashes separated by a pipe \\", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "peers", - is_optional: false, - is_list: false, - description: Some( - "The peer to add, or multiple peers separated by a pipe \\", - ), - type_description: None, - }, - ), - ], - optional: [], - }, - ), - return_type: None, url: "addPeers", + types: CompositeTypes { + composite_types: [ + Parameters( + TypeWithoutName { + types: [ + String( + TypeInfo { + name: "hashes", + is_optional: false, + is_list: false, + description: Some( + "The hash of the torrent, or multiple hashes separated by a pipe \\", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "peers", + is_optional: false, + is_list: false, + description: Some( + "The peer to add, or multiple peers separated by a pipe \\", + ), + type_description: None, + }, + ), + ], + }, + ), + ], + }, }, ApiMethod { name: "increasePrio", description: None, - parameters: Some( - ApiParameters { - mandatory: [ - String( - TypeInfo { - name: "hashes", - is_optional: false, - is_list: false, - description: Some( - "The hashes of the torrents you want to increase the priority of. hashes can contain multiple hashes separated by \\", - ), - type_description: None, - }, - ), - ], - optional: [], - }, - ), - return_type: None, url: "increasePrio", + types: CompositeTypes { + composite_types: [ + Parameters( + TypeWithoutName { + types: [ + String( + TypeInfo { + name: "hashes", + is_optional: false, + is_list: false, + description: Some( + "The hashes of the torrents you want to increase the priority of. hashes can contain multiple hashes separated by \\", + ), + type_description: None, + }, + ), + ], + }, + ), + ], + }, }, ApiMethod { name: "decreasePrio", description: None, - parameters: Some( - ApiParameters { - mandatory: [ - String( - TypeInfo { - name: "hashes", - is_optional: false, - is_list: false, - description: Some( - "The hashes of the torrents you want to decrease the priority of. hashes can contain multiple hashes separated by \\", - ), - type_description: None, - }, - ), - ], - optional: [], - }, - ), - return_type: None, url: "decreasePrio", + types: CompositeTypes { + composite_types: [ + Parameters( + TypeWithoutName { + types: [ + String( + TypeInfo { + name: "hashes", + is_optional: false, + is_list: false, + description: Some( + "The hashes of the torrents you want to decrease the priority of. hashes can contain multiple hashes separated by \\", + ), + type_description: None, + }, + ), + ], + }, + ), + ], + }, }, ApiMethod { name: "topPrio", description: None, - parameters: Some( - ApiParameters { - mandatory: [ - String( - TypeInfo { - name: "hashes", - is_optional: false, - is_list: false, - description: Some( - "The hashes of the torrents you want to set to the maximum priority. hashes can contain multiple hashes separated by \\", - ), - type_description: None, - }, - ), - ], - optional: [], - }, - ), - return_type: None, url: "topPrio", + types: CompositeTypes { + composite_types: [ + Parameters( + TypeWithoutName { + types: [ + String( + TypeInfo { + name: "hashes", + is_optional: false, + is_list: false, + description: Some( + "The hashes of the torrents you want to set to the maximum priority. hashes can contain multiple hashes separated by \\", + ), + type_description: None, + }, + ), + ], + }, + ), + ], + }, }, ApiMethod { name: "bottomPrio", description: None, - parameters: Some( - ApiParameters { - mandatory: [ - String( - TypeInfo { - name: "hashes", - is_optional: false, - is_list: false, - description: Some( - "The hashes of the torrents you want to set to the minimum priority. hashes can contain multiple hashes separated by \\", - ), - type_description: None, - }, - ), - ], - optional: [], - }, - ), - return_type: None, url: "bottomPrio", + types: CompositeTypes { + composite_types: [ + Parameters( + TypeWithoutName { + types: [ + String( + TypeInfo { + name: "hashes", + is_optional: false, + is_list: false, + description: Some( + "The hashes of the torrents you want to set to the minimum priority. hashes can contain multiple hashes separated by \\", + ), + type_description: None, + }, + ), + ], + }, + ), + ], + }, }, ApiMethod { name: "filePrio", description: None, - parameters: Some( - ApiParameters { - mandatory: [ - String( - TypeInfo { - name: "hash", - is_optional: false, - is_list: false, - description: Some( - "The hash of the torrent", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "id", - is_optional: false, - is_list: false, - description: Some( - "File ids, separated by \\", - ), - type_description: None, - }, - ), - Number( - TypeInfo { - name: "priority", - is_optional: false, - is_list: false, - description: Some( - "File priority to set (consult [torrent contents API](#get-torrent-contents) for possible values)", - ), - type_description: None, - }, - ), - ], - optional: [], - }, - ), - return_type: None, url: "filePrio", + types: CompositeTypes { + composite_types: [ + Parameters( + TypeWithoutName { + types: [ + String( + TypeInfo { + name: "hash", + is_optional: false, + is_list: false, + description: Some( + "The hash of the torrent", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "id", + is_optional: false, + is_list: false, + description: Some( + "File ids, separated by \\", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "priority", + is_optional: false, + is_list: false, + description: Some( + "File priority to set (consult [torrent contents API](#get-torrent-contents) for possible values)", + ), + type_description: None, + }, + ), + ], + }, + ), + ], + }, }, ApiMethod { name: "downloadLimit", description: None, - parameters: None, - return_type: None, url: "downloadLimit", + types: CompositeTypes { + composite_types: [], + }, }, ApiMethod { name: "setShareLimits", description: None, - parameters: None, - return_type: None, url: "setShareLimits", + types: CompositeTypes { + composite_types: [], + }, }, ApiMethod { name: "uploadLimit", description: None, - parameters: None, - return_type: None, url: "uploadLimit", + types: CompositeTypes { + composite_types: [], + }, }, ApiMethod { name: "setUploadLimit", description: None, - parameters: None, - return_type: None, url: "setUploadLimit", + types: CompositeTypes { + composite_types: [], + }, }, ApiMethod { name: "setLocation", description: None, - parameters: None, - return_type: None, url: "setLocation", + types: CompositeTypes { + composite_types: [], + }, }, ApiMethod { name: "rename", description: None, - parameters: None, - return_type: None, url: "rename", + types: CompositeTypes { + composite_types: [], + }, }, ApiMethod { name: "setCategory", description: None, - parameters: None, - return_type: None, url: "setCategory", + types: CompositeTypes { + composite_types: [], + }, }, ApiMethod { name: "categories", description: None, - parameters: None, - return_type: None, url: "categories", + types: CompositeTypes { + composite_types: [], + }, }, ApiMethod { name: "createCategory", description: None, - parameters: None, - return_type: None, url: "createCategory", + types: CompositeTypes { + composite_types: [], + }, }, ApiMethod { name: "editCategory", description: None, - parameters: None, - return_type: None, url: "editCategory", + types: CompositeTypes { + composite_types: [], + }, }, ApiMethod { name: "removeCategories", description: None, - parameters: None, - return_type: None, url: "removeCategories", + types: CompositeTypes { + composite_types: [], + }, }, ApiMethod { name: "addTags", description: None, - parameters: None, - return_type: None, url: "addTags", + types: CompositeTypes { + composite_types: [], + }, }, ApiMethod { name: "removeTags", description: None, - parameters: None, - return_type: None, url: "removeTags", + types: CompositeTypes { + composite_types: [], + }, }, ApiMethod { name: "tags", description: None, - parameters: None, - return_type: None, url: "tags", + types: CompositeTypes { + composite_types: [], + }, }, ApiMethod { name: "createTags", description: None, - parameters: None, - return_type: None, url: "createTags", + types: CompositeTypes { + composite_types: [], + }, }, ApiMethod { name: "deleteTags", description: None, - parameters: None, - return_type: None, url: "deleteTags", + types: CompositeTypes { + composite_types: [], + }, }, ApiMethod { name: "setAutoManagement", description: None, - parameters: None, - return_type: None, url: "setAutoManagement", + types: CompositeTypes { + composite_types: [], + }, }, ApiMethod { name: "toggleSequentialDownload", description: None, - parameters: Some( - ApiParameters { - mandatory: [ - String( - TypeInfo { - name: "hashes", - is_optional: false, - is_list: false, - description: Some( - "The hashes of the torrents you want to toggle sequential download for. hashes can contain multiple hashes separated by \\", - ), - type_description: None, - }, - ), - ], - optional: [], - }, - ), - return_type: None, url: "toggleSequentialDownload", + types: CompositeTypes { + composite_types: [ + Parameters( + TypeWithoutName { + types: [ + String( + TypeInfo { + name: "hashes", + is_optional: false, + is_list: false, + description: Some( + "The hashes of the torrents you want to toggle sequential download for. hashes can contain multiple hashes separated by \\", + ), + type_description: None, + }, + ), + ], + }, + ), + ], + }, }, ApiMethod { name: "toggleFirstLastPiecePrio", description: None, - parameters: Some( - ApiParameters { - mandatory: [ - String( - TypeInfo { - name: "hashes", - is_optional: false, - is_list: false, - description: Some( - "The hashes of the torrents you want to toggle the first/last piece priority for. hashes can contain multiple hashes separated by \\", - ), - type_description: None, - }, - ), - ], - optional: [], - }, - ), - return_type: None, url: "toggleFirstLastPiecePrio", + types: CompositeTypes { + composite_types: [ + Parameters( + TypeWithoutName { + types: [ + String( + TypeInfo { + name: "hashes", + is_optional: false, + is_list: false, + description: Some( + "The hashes of the torrents you want to toggle the first/last piece priority for. hashes can contain multiple hashes separated by \\", + ), + type_description: None, + }, + ), + ], + }, + ), + ], + }, }, ApiMethod { name: "setForceStart", description: None, - parameters: None, - return_type: None, url: "setForceStart", + types: CompositeTypes { + composite_types: [], + }, }, ApiMethod { name: "setSuperSeeding", description: None, - parameters: None, - return_type: None, url: "setSuperSeeding", + types: CompositeTypes { + composite_types: [], + }, }, ApiMethod { name: "renameFile", description: None, - parameters: Some( - ApiParameters { - mandatory: [ - String( - TypeInfo { - name: "hash", - is_optional: false, - is_list: false, - description: Some( - "The hash of the torrent", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "oldPath", - is_optional: false, - is_list: false, - description: Some( - "The old path of the torrent", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "newPath", - is_optional: false, - is_list: false, - description: Some( - "The new path to use for the file", - ), - type_description: None, - }, - ), - ], - optional: [], - }, - ), - return_type: None, url: "renameFile", + types: CompositeTypes { + composite_types: [ + Parameters( + TypeWithoutName { + types: [ + String( + TypeInfo { + name: "hash", + is_optional: false, + is_list: false, + description: Some( + "The hash of the torrent", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "oldPath", + is_optional: false, + is_list: false, + description: Some( + "The old path of the torrent", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "newPath", + is_optional: false, + is_list: false, + description: Some( + "The new path to use for the file", + ), + type_description: None, + }, + ), + ], + }, + ), + ], + }, }, ApiMethod { name: "renameFolder", description: None, - parameters: Some( - ApiParameters { - mandatory: [ - String( - TypeInfo { - name: "hash", - is_optional: false, - is_list: false, - description: Some( - "The hash of the torrent", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "oldPath", - is_optional: false, - is_list: false, - description: Some( - "The old path of the torrent", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "newPath", - is_optional: false, - is_list: false, - description: Some( - "The new path to use for the file", - ), - type_description: None, - }, - ), - ], - optional: [], - }, - ), - return_type: None, url: "renameFolder", + types: CompositeTypes { + composite_types: [ + Parameters( + TypeWithoutName { + types: [ + String( + TypeInfo { + name: "hash", + is_optional: false, + is_list: false, + description: Some( + "The hash of the torrent", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "oldPath", + is_optional: false, + is_list: false, + description: Some( + "The old path of the torrent", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "newPath", + is_optional: false, + is_list: false, + description: Some( + "The new path to use for the file", + ), + type_description: None, + }, + ), + ], + }, + ), + ], + }, }, ], description: Some( @@ -5295,313 +3103,333 @@ ApiMethod { name: "addFolder", description: None, - parameters: Some( - ApiParameters { - mandatory: [ - String( - TypeInfo { - name: "path", - is_optional: false, - is_list: false, - description: Some( - "Full path of added folder (e.g. \"The Pirate Bay\\Top100\")", - ), - type_description: None, - }, - ), - ], - optional: [], - }, - ), - return_type: None, url: "addFolder", + types: CompositeTypes { + composite_types: [ + Parameters( + TypeWithoutName { + types: [ + String( + TypeInfo { + name: "path", + is_optional: false, + is_list: false, + description: Some( + "Full path of added folder (e.g. \"The Pirate Bay\\Top100\")", + ), + type_description: None, + }, + ), + ], + }, + ), + ], + }, }, ApiMethod { name: "addFeed", description: None, - parameters: Some( - ApiParameters { - mandatory: [ - String( - TypeInfo { - name: "url", - is_optional: false, - is_list: false, - description: Some( - "URL of RSS feed (e.g. \"[http://thepiratebay.org/rss//top100/200](http://thepiratebay.org/rss//top100/200)\")", - ), - type_description: None, - }, - ), - ], - optional: [ - String( - TypeInfo { - name: "path", - is_optional: true, - is_list: false, - description: Some( - "Full path of added folder (e.g. \"The Pirate Bay\\Top100\\Video\")", - ), - type_description: None, - }, - ), - ], - }, - ), - return_type: None, url: "addFeed", + types: CompositeTypes { + composite_types: [ + Parameters( + TypeWithoutName { + types: [ + String( + TypeInfo { + name: "url", + is_optional: false, + is_list: false, + description: Some( + "URL of RSS feed (e.g. \"[http://thepiratebay.org/rss//top100/200](http://thepiratebay.org/rss//top100/200)\")", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "path", + is_optional: true, + is_list: false, + description: Some( + "Full path of added folder (e.g. \"The Pirate Bay\\Top100\\Video\")", + ), + type_description: None, + }, + ), + ], + }, + ), + ], + }, }, ApiMethod { name: "removeItem", description: None, - parameters: Some( - ApiParameters { - mandatory: [ - String( - TypeInfo { - name: "path", - is_optional: false, - is_list: false, - description: Some( - "Full path of removed item (e.g. \"The Pirate Bay\\Top100\")", - ), - type_description: None, - }, - ), - ], - optional: [], - }, - ), - return_type: None, url: "removeItem", + types: CompositeTypes { + composite_types: [ + Parameters( + TypeWithoutName { + types: [ + String( + TypeInfo { + name: "path", + is_optional: false, + is_list: false, + description: Some( + "Full path of removed item (e.g. \"The Pirate Bay\\Top100\")", + ), + type_description: None, + }, + ), + ], + }, + ), + ], + }, }, ApiMethod { name: "moveItem", description: None, - parameters: Some( - ApiParameters { - mandatory: [ - String( - TypeInfo { - name: "itemPath", - is_optional: false, - is_list: false, - description: Some( - "Current full path of item (e.g. \"The Pirate Bay\\Top100\")", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "destPath", - is_optional: false, - is_list: false, - description: Some( - "New full path of item (e.g. \"The Pirate Bay\")", - ), - type_description: None, - }, - ), - ], - optional: [], - }, - ), - return_type: None, url: "moveItem", + types: CompositeTypes { + composite_types: [ + Parameters( + TypeWithoutName { + types: [ + String( + TypeInfo { + name: "itemPath", + is_optional: false, + is_list: false, + description: Some( + "Current full path of item (e.g. \"The Pirate Bay\\Top100\")", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "destPath", + is_optional: false, + is_list: false, + description: Some( + "New full path of item (e.g. \"The Pirate Bay\")", + ), + type_description: None, + }, + ), + ], + }, + ), + ], + }, }, ApiMethod { name: "items", description: None, - parameters: Some( - ApiParameters { - mandatory: [], - optional: [ - Bool( - TypeInfo { - name: "withData", - is_optional: true, - is_list: false, - description: Some( - "True if you need current feed articles", - ), - type_description: None, - }, - ), - ], - }, - ), - return_type: None, url: "items", + types: CompositeTypes { + composite_types: [ + Parameters( + TypeWithoutName { + types: [ + Bool( + TypeInfo { + name: "withData", + is_optional: true, + is_list: false, + description: Some( + "True if you need current feed articles", + ), + type_description: None, + }, + ), + ], + }, + ), + ], + }, }, ApiMethod { name: "markAsRead", description: None, - parameters: Some( - ApiParameters { - mandatory: [ - String( - TypeInfo { - name: "itemPath", - is_optional: false, - is_list: false, - description: Some( - "Current full path of item (e.g. \"The Pirate Bay\\Top100\")", - ), - type_description: None, - }, - ), - ], - optional: [ - String( - TypeInfo { - name: "articleId", - is_optional: true, - is_list: false, - description: Some( - "ID of article", - ), - type_description: None, - }, - ), - ], - }, - ), - return_type: None, url: "markAsRead", + types: CompositeTypes { + composite_types: [ + Parameters( + TypeWithoutName { + types: [ + String( + TypeInfo { + name: "itemPath", + is_optional: false, + is_list: false, + description: Some( + "Current full path of item (e.g. \"The Pirate Bay\\Top100\")", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "articleId", + is_optional: true, + is_list: false, + description: Some( + "ID of article", + ), + type_description: None, + }, + ), + ], + }, + ), + ], + }, }, ApiMethod { name: "refreshItem", description: None, - parameters: Some( - ApiParameters { - mandatory: [ - String( - TypeInfo { - name: "itemPath", - is_optional: false, - is_list: false, - description: Some( - "Current full path of item (e.g. \"The Pirate Bay\\Top100\")", - ), - type_description: None, - }, - ), - ], - optional: [], - }, - ), - return_type: None, url: "refreshItem", + types: CompositeTypes { + composite_types: [ + Parameters( + TypeWithoutName { + types: [ + String( + TypeInfo { + name: "itemPath", + is_optional: false, + is_list: false, + description: Some( + "Current full path of item (e.g. \"The Pirate Bay\\Top100\")", + ), + type_description: None, + }, + ), + ], + }, + ), + ], + }, }, ApiMethod { name: "setRule", description: None, - parameters: Some( - ApiParameters { - mandatory: [ - String( - TypeInfo { - name: "ruleName", - is_optional: false, - is_list: false, - description: Some( - "Rule name (e.g. \"Punisher\")", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "ruleDef", - is_optional: false, - is_list: false, - description: Some( - "JSON encoded rule definition", - ), - type_description: None, - }, - ), - ], - optional: [], - }, - ), - return_type: None, url: "setRule", + types: CompositeTypes { + composite_types: [ + Parameters( + TypeWithoutName { + types: [ + String( + TypeInfo { + name: "ruleName", + is_optional: false, + is_list: false, + description: Some( + "Rule name (e.g. \"Punisher\")", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "ruleDef", + is_optional: false, + is_list: false, + description: Some( + "JSON encoded rule definition", + ), + type_description: None, + }, + ), + ], + }, + ), + ], + }, }, ApiMethod { name: "renameRule", description: None, - parameters: Some( - ApiParameters { - mandatory: [ - String( - TypeInfo { - name: "ruleName", - is_optional: false, - is_list: false, - description: Some( - "Rule name (e.g. \"Punisher\")", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "newRuleName", - is_optional: false, - is_list: false, - description: Some( - "New rule name (e.g. \"The Punisher\")", - ), - type_description: None, - }, - ), - ], - optional: [], - }, - ), - return_type: None, url: "renameRule", + types: CompositeTypes { + composite_types: [ + Parameters( + TypeWithoutName { + types: [ + String( + TypeInfo { + name: "ruleName", + is_optional: false, + is_list: false, + description: Some( + "Rule name (e.g. \"Punisher\")", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "newRuleName", + is_optional: false, + is_list: false, + description: Some( + "New rule name (e.g. \"The Punisher\")", + ), + type_description: None, + }, + ), + ], + }, + ), + ], + }, }, ApiMethod { name: "removeRule", description: None, - parameters: Some( - ApiParameters { - mandatory: [ - String( - TypeInfo { - name: "ruleName", - is_optional: false, - is_list: false, - description: Some( - "Rule name (e.g. \"Punisher\")", - ), - type_description: None, - }, - ), - ], - optional: [], - }, - ), - return_type: None, url: "removeRule", + types: CompositeTypes { + composite_types: [ + Parameters( + TypeWithoutName { + types: [ + String( + TypeInfo { + name: "ruleName", + is_optional: false, + is_list: false, + description: Some( + "Rule name (e.g. \"Punisher\")", + ), + type_description: None, + }, + ), + ], + }, + ), + ], + }, }, ApiMethod { name: "rules", description: None, - parameters: None, - return_type: None, url: "rules", + types: CompositeTypes { + composite_types: [], + }, }, ApiMethod { name: "matchingArticles", description: None, - parameters: None, - return_type: None, url: "matchingArticles", + types: CompositeTypes { + composite_types: [], + }, }, ], description: Some( @@ -5617,489 +3445,542 @@ description: Some( "The response is a JSON object with the following fields\n\n\nExample:\n\n```JSON\n{\n \"id\": 12345\n}\n```", ), - parameters: Some( - ApiParameters { - mandatory: [ - String( - TypeInfo { - name: "pattern", - is_optional: false, - is_list: false, - description: Some( - "Pattern to search for (e.g. \"Ubuntu 18.04\")", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "plugins", - is_optional: false, - is_list: false, - description: Some( - "Plugins to use for searching (e.g. \"legittorrents\"). Supports multiple plugins separated by \\", - ), - type_description: None, - }, - ), - String( - TypeInfo { - name: "category", - is_optional: false, - is_list: false, - description: Some( - "Categories to limit your search to (e.g. \"legittorrents\"). Available categories depend on the specified plugins. Also supports all", - ), - type_description: None, - }, - ), - ], - optional: [], - }, - ), - return_type: Some( - ReturnType { - is_list: false, - parameters: [ - ReturnTypeParameter { - name: "id", - description: "ID of the search job", - return_type: Number( - TypeInfo { - name: "id", - is_optional: false, - is_list: false, - description: Some( - "ID of the search job", - ), - type_description: None, - }, - ), - }, - ], - }, - ), url: "start", + types: CompositeTypes { + composite_types: [ + Parameters( + TypeWithoutName { + types: [ + String( + TypeInfo { + name: "pattern", + is_optional: false, + is_list: false, + description: Some( + "Pattern to search for (e.g. \"Ubuntu 18.04\")", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "plugins", + is_optional: false, + is_list: false, + description: Some( + "Plugins to use for searching (e.g. \"legittorrents\"). Supports multiple plugins separated by \\", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "category", + is_optional: false, + is_list: false, + description: Some( + "Categories to limit your search to (e.g. \"legittorrents\"). Available categories depend on the specified plugins. Also supports all", + ), + type_description: None, + }, + ), + ], + }, + ), + Response( + TypeWithoutName { + types: [ + Number( + TypeInfo { + name: "id", + is_optional: false, + is_list: false, + description: Some( + "ID of the search job", + ), + type_description: None, + }, + ), + ], + }, + ), + ], + }, }, ApiMethod { name: "stop", description: None, - parameters: Some( - ApiParameters { - mandatory: [ - Number( - TypeInfo { - name: "id", - is_optional: false, - is_list: false, - description: Some( - "ID of the search job", - ), - type_description: None, - }, - ), - ], - optional: [], - }, - ), - return_type: None, url: "stop", + types: CompositeTypes { + composite_types: [ + Parameters( + TypeWithoutName { + types: [ + Number( + TypeInfo { + name: "id", + is_optional: false, + is_list: false, + description: Some( + "ID of the search job", + ), + type_description: None, + }, + ), + ], + }, + ), + ], + }, }, ApiMethod { name: "status", description: Some( "The response is a JSON array of objects containing the following fields\n\n\nExample:\n\n```JSON\n[\n {\n \"id\": 12345,\n \"status\": \"Running\",\n \"total\": 170\n }\n]\n```", ), - parameters: Some( - ApiParameters { - mandatory: [], - optional: [ - Number( - TypeInfo { - name: "id", - is_optional: true, - is_list: false, - description: Some( - "ID of the search job. If not specified, all search jobs are returned", - ), - type_description: None, - }, - ), - ], - }, - ), - return_type: Some( - ReturnType { - is_list: true, - parameters: [ - ReturnTypeParameter { - name: "id", - description: "ID of the search job", - return_type: Number( - TypeInfo { - name: "id", - is_optional: false, - is_list: false, - description: Some( - "ID of the search job", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "status", - description: "Current status of the search job (either Running or Stopped)", - return_type: String( - TypeInfo { - name: "status", - is_optional: false, - is_list: false, - description: Some( - "Current status of the search job (either Running or Stopped)", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "total", - description: "Total number of results. If the status is Running this number may contineu to increase", - return_type: Number( - TypeInfo { - name: "total", - is_optional: false, - is_list: false, - description: Some( - "Total number of results. If the status is Running this number may contineu to increase", - ), - type_description: None, - }, - ), - }, - ], - }, - ), url: "status", + types: CompositeTypes { + composite_types: [ + Parameters( + TypeWithoutName { + types: [ + Number( + TypeInfo { + name: "id", + is_optional: true, + is_list: false, + description: Some( + "ID of the search job. If not specified, all search jobs are returned", + ), + type_description: None, + }, + ), + ], + }, + ), + Response( + TypeWithoutName { + types: [ + Number( + TypeInfo { + name: "id", + is_optional: false, + is_list: false, + description: Some( + "ID of the search job", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "status", + is_optional: false, + is_list: false, + description: Some( + "Current status of the search job (either Running or Stopped)", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "total", + is_optional: false, + is_list: false, + description: Some( + "Total number of results. If the status is Running this number may contineu to increase", + ), + type_description: None, + }, + ), + ], + }, + ), + ], + }, }, ApiMethod { name: "results", description: Some( "The response is a JSON object with the following fields\n\n\n\n\nExample:\n\n```JSON\n{\n \"results\": [\n {\n \"descrLink\": \"http://www.legittorrents.info/index.php?page=torrent-details&id=8d5f512e1acb687029b8d7cc6c5a84dce51d7a41\",\n \"fileName\": \"Ubuntu-10.04-32bit-NeTV.ova\",\n \"fileSize\": -1,\n \"fileUrl\": \"http://www.legittorrents.info/download.php?id=8d5f512e1acb687029b8d7cc6c5a84dce51d7a41&f=Ubuntu-10.04-32bit-NeTV.ova.torrent\",\n \"nbLeechers\": 1,\n \"nbSeeders\": 0,\n \"siteUrl\": \"http://www.legittorrents.info\"\n },\n {\n \"descrLink\": \"http://www.legittorrents.info/index.php?page=torrent-details&id=d5179f53e105dc2c2401bcfaa0c2c4936a6aa475\",\n \"fileName\": \"mangOH-Legato-17_06-Ubuntu-16_04.ova\",\n \"fileSize\": -1,\n \"fileUrl\": \"http://www.legittorrents.info/download.php?id=d5179f53e105dc2c2401bcfaa0c2c4936a6aa475&f=mangOH-Legato-17_06-Ubuntu-16_04.ova.torrent\",\n \"nbLeechers\": 0,\n \"nbSeeders\": 59,\n \"siteUrl\": \"http://www.legittorrents.info\"\n }\n ],\n \"status\": \"Running\",\n \"total\": 2\n}\n```", ), - parameters: Some( - ApiParameters { - mandatory: [ - Number( - TypeInfo { - name: "id", - is_optional: false, - is_list: false, - description: Some( - "ID of the search job", - ), - type_description: None, - }, - ), - ], - optional: [ - Number( - TypeInfo { - name: "limit", - is_optional: true, - is_list: false, - description: Some( - "max number of results to return. 0 or negative means no limit", - ), - type_description: None, - }, - ), - Number( - TypeInfo { - name: "offset", - is_optional: true, - is_list: false, - description: Some( - "result to start at. A negative number means count backwards (e.g. -2 returns the 2 most recent results)", - ), - type_description: None, - }, - ), - ], - }, - ), - return_type: Some( - ReturnType { - is_list: false, - parameters: [ - ReturnTypeParameter { - name: "results", - description: "Array of result objects- see table below", - return_type: StringArray( - TypeInfo { - name: "results", - is_optional: false, - is_list: false, - description: Some( - "Array of result objects- see table below", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "status", - description: "Current status of the search job (either Running or Stopped)", - return_type: String( - TypeInfo { - name: "status", - is_optional: false, - is_list: false, - description: Some( - "Current status of the search job (either Running or Stopped)", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "total", - description: "Total number of results. If the status is Running this number may continue to increase", - return_type: Number( - TypeInfo { - name: "total", - is_optional: false, - is_list: false, - description: Some( - "Total number of results. If the status is Running this number may continue to increase", - ), - type_description: None, - }, - ), - }, - ], - }, - ), url: "results", + types: CompositeTypes { + composite_types: [ + Parameters( + TypeWithoutName { + types: [ + Number( + TypeInfo { + name: "id", + is_optional: false, + is_list: false, + description: Some( + "ID of the search job", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "limit", + is_optional: true, + is_list: false, + description: Some( + "max number of results to return. 0 or negative means no limit", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "offset", + is_optional: true, + is_list: false, + description: Some( + "result to start at. A negative number means count backwards (e.g. -2 returns the 2 most recent results)", + ), + type_description: None, + }, + ), + ], + }, + ), + Object( + TypeWithName { + name: "Result", + types: [ + String( + TypeInfo { + name: "descrLink", + is_optional: false, + is_list: false, + description: Some( + "URL of the torrent's description page", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "fileName", + is_optional: false, + is_list: false, + description: Some( + "Name of the file", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "fileSize", + is_optional: false, + is_list: false, + description: Some( + "Size of the file in Bytes", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "fileUrl", + is_optional: false, + is_list: false, + description: Some( + "Torrent download link (usually either .torrent file or magnet link)", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "nbLeechers", + is_optional: false, + is_list: false, + description: Some( + "Number of leechers", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "nbSeeders", + is_optional: false, + is_list: false, + description: Some( + "Number of seeders", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "siteUrl", + is_optional: false, + is_list: false, + description: Some( + "URL of the torrent site", + ), + type_description: None, + }, + ), + ], + }, + ), + Response( + TypeWithoutName { + types: [ + Object( + Object { + type_info: TypeInfo { + name: "results", + is_optional: false, + is_list: false, + description: Some( + "Array of result objects- see table below", + ), + type_description: None, + }, + ref_type: "Result", + }, + ), + String( + TypeInfo { + name: "status", + is_optional: false, + is_list: false, + description: Some( + "Current status of the search job (either Running or Stopped)", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "total", + is_optional: false, + is_list: false, + description: Some( + "Total number of results. If the status is Running this number may continue to increase", + ), + type_description: None, + }, + ), + ], + }, + ), + ], + }, }, ApiMethod { name: "delete", description: None, - parameters: Some( - ApiParameters { - mandatory: [ - Number( - TypeInfo { - name: "id", - is_optional: false, - is_list: false, - description: Some( - "ID of the search job", - ), - type_description: None, - }, - ), - ], - optional: [], - }, - ), - return_type: None, url: "delete", + types: CompositeTypes { + composite_types: [ + Parameters( + TypeWithoutName { + types: [ + Number( + TypeInfo { + name: "id", + is_optional: false, + is_list: false, + description: Some( + "ID of the search job", + ), + type_description: None, + }, + ), + ], + }, + ), + ], + }, }, ApiMethod { name: "plugins", description: Some( "The response is a JSON array of objects containing the following fields\n\n\n```JSON\n[\n {\n \"enabled\": true,\n \"fullName\": \"Legit Torrents\",\n \"name\": \"legittorrents\",\n \"supportedCategories\": [{\n \"id\": \"all\",\n \"name\": \"All categories\"\n }, {\n \"id\": \"anime\",\n \"name\": \"Anime\"\n }, {\n \"id\": \"books\",\n \"name\": \"Books\"\n }, {\n \"id\": \"games\",\n \"name\": \"Games\"\n }, {\n \"id\": \"movies\",\n \"name\": \"Movies\"\n }, {\n \"id\": \"music\",\n \"name\": \"Music\"\n }, {\n \"id\": \"tv\",\n \"name\": \"TV shows\"\n }],\n \"url\": \"http://www.legittorrents.info\",\n \"version\": \"2.3\"\n }\n]\n```", ), - parameters: None, - return_type: Some( - ReturnType { - is_list: true, - parameters: [ - ReturnTypeParameter { - name: "enabled", - description: "Whether the plugin is enabled", - return_type: Bool( - TypeInfo { - name: "enabled", - is_optional: false, - is_list: false, - description: Some( - "Whether the plugin is enabled", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "fullName", - description: "Full name of the plugin", - return_type: String( - TypeInfo { - name: "fullName", - is_optional: false, - is_list: false, - description: Some( - "Full name of the plugin", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "name", - description: "Short name of the plugin", - return_type: String( - TypeInfo { - name: "name", - is_optional: false, - is_list: false, - description: Some( - "Short name of the plugin", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "supportedCategories", - description: "List of category objects", - return_type: StringArray( - TypeInfo { - name: "supportedCategories", - is_optional: false, - is_list: false, - description: Some( - "List of category objects", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "url", - description: "URL of the torrent site", - return_type: String( - TypeInfo { - name: "url", - is_optional: false, - is_list: false, - description: Some( - "URL of the torrent site", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "version", - description: "Installed version of the plugin", - return_type: String( - TypeInfo { - name: "version", - is_optional: false, - is_list: false, - description: Some( - "Installed version of the plugin", - ), - type_description: None, - }, - ), - }, - ], - }, - ), url: "plugins", + types: CompositeTypes { + composite_types: [ + Response( + TypeWithoutName { + types: [ + Bool( + TypeInfo { + name: "enabled", + is_optional: false, + is_list: false, + description: Some( + "Whether the plugin is enabled", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "fullName", + is_optional: false, + is_list: false, + description: Some( + "Full name of the plugin", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "name", + is_optional: false, + is_list: false, + description: Some( + "Short name of the plugin", + ), + type_description: None, + }, + ), + StringArray( + TypeInfo { + name: "supportedCategories", + is_optional: false, + is_list: false, + description: Some( + "List of category objects", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "url", + is_optional: false, + is_list: false, + description: Some( + "URL of the torrent site", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "version", + is_optional: false, + is_list: false, + description: Some( + "Installed version of the plugin", + ), + type_description: None, + }, + ), + ], + }, + ), + ], + }, }, ApiMethod { name: "installPlugin", description: None, - parameters: Some( - ApiParameters { - mandatory: [ - String( - TypeInfo { - name: "sources", - is_optional: false, - is_list: false, - description: Some( - "Url or file path of the plugin to install (e.g. \"[https://raw.githubusercontent.com/qbittorrent/search-plugins/master/nova3/engines/legittorrents.py](https://raw.githubusercontent.com/qbittorrent/search-plugins/master/nova3/engines/legittorrents.py)\"). Supports multiple sources separated by \\", - ), - type_description: None, - }, - ), - ], - optional: [], - }, - ), - return_type: None, url: "installPlugin", + types: CompositeTypes { + composite_types: [ + Parameters( + TypeWithoutName { + types: [ + String( + TypeInfo { + name: "sources", + is_optional: false, + is_list: false, + description: Some( + "Url or file path of the plugin to install (e.g. \"[https://raw.githubusercontent.com/qbittorrent/search-plugins/master/nova3/engines/legittorrents.py](https://raw.githubusercontent.com/qbittorrent/search-plugins/master/nova3/engines/legittorrents.py)\"). Supports multiple sources separated by \\", + ), + type_description: None, + }, + ), + ], + }, + ), + ], + }, }, ApiMethod { name: "uninstallPlugin", description: None, - parameters: Some( - ApiParameters { - mandatory: [ - String( - TypeInfo { - name: "names", - is_optional: false, - is_list: false, - description: Some( - "Name of the plugin to uninstall (e.g. \"legittorrents\"). Supports multiple names separated by \\", - ), - type_description: None, - }, - ), - ], - optional: [], - }, - ), - return_type: None, url: "uninstallPlugin", + types: CompositeTypes { + composite_types: [ + Parameters( + TypeWithoutName { + types: [ + String( + TypeInfo { + name: "names", + is_optional: false, + is_list: false, + description: Some( + "Name of the plugin to uninstall (e.g. \"legittorrents\"). Supports multiple names separated by \\", + ), + type_description: None, + }, + ), + ], + }, + ), + ], + }, }, ApiMethod { name: "enablePlugin", description: None, - parameters: Some( - ApiParameters { - mandatory: [ - String( - TypeInfo { - name: "names", - is_optional: false, - is_list: false, - description: Some( - "Name of the plugin to enable/disable (e.g. \"legittorrents\"). Supports multiple names separated by \\", - ), - type_description: None, - }, - ), - Bool( - TypeInfo { - name: "enable", - is_optional: false, - is_list: false, - description: Some( - "Whether the plugins should be enabled", - ), - type_description: None, - }, - ), - ], - optional: [], - }, - ), - return_type: None, url: "enablePlugin", + types: CompositeTypes { + composite_types: [ + Parameters( + TypeWithoutName { + types: [ + String( + TypeInfo { + name: "names", + is_optional: false, + is_list: false, + description: Some( + "Name of the plugin to enable/disable (e.g. \"legittorrents\"). Supports multiple names separated by \\", + ), + type_description: None, + }, + ), + Bool( + TypeInfo { + name: "enable", + is_optional: false, + is_list: false, + description: Some( + "Whether the plugins should be enabled", + ), + type_description: None, + }, + ), + ], + }, + ), + ], + }, }, ApiMethod { name: "updatePlugins", description: None, - parameters: None, - return_type: None, url: "updatePlugins", + types: CompositeTypes { + composite_types: [], + }, }, ], description: Some( diff --git a/qbittorrent-web-api-gen/src/generate/group/mod.rs b/qbittorrent-web-api-gen/src/generate/group/mod.rs index bf4c911..d4bb2f0 100644 --- a/qbittorrent-web-api-gen/src/generate/group/mod.rs +++ b/qbittorrent-web-api-gen/src/generate/group/mod.rs @@ -1,14 +1,11 @@ -mod method; - -use crate::parser; +use crate::{parser, types}; use case::CaseExt; +use proc_macro2::{Ident, TokenStream}; use quote::quote; -use self::method::generate_methods; - use super::{skeleton::auth_ident, util}; -pub fn generate_groups(groups: Vec) -> proc_macro2::TokenStream { +pub fn generate_groups(groups: Vec) -> TokenStream { let gr = groups .iter() // implemented manually @@ -20,30 +17,410 @@ pub fn generate_groups(groups: Vec) -> proc_macro2::TokenStrea } } -fn generate_group(group: &parser::ApiGroup) -> proc_macro2::TokenStream { - let group_name_camel = util::to_ident(&group.name.to_camel()); - let group_name_snake = util::to_ident(&group.name.to_snake()); - let auth = auth_ident(); - let methods = generate_methods(group, &auth, &group_name_camel); - - let group_method = util::add_docs( - &group.description, - quote! { - pub fn #group_name_snake(&self) -> #group_name_camel { - #group_name_camel::new(self) - } - }, - ); +fn generate_group(group: &parser::ApiGroup) -> TokenStream { + let group = group.generate(); quote! { - pub struct #group_name_camel<'a> { - auth: &'a #auth, + #group + } +} + +impl parser::ApiGroup { + fn generate(&self) -> TokenStream { + let struct_name = self.struct_name(); + let group_name_snake = self.name_snake(); + let group_methods = self.generate_group_methods(); + + let group_struct = self.group_struct(); + let group_factory = self.group_factory(); + let auth = auth_ident(); + + quote! { + pub mod #group_name_snake { + impl <'a> #struct_name<'a> { + pub fn new(auth: &'a super::#auth) -> Self { + Self { auth } + } + } + + #group_struct + #group_factory + + #(#group_methods)* + } } + } - #methods + fn generate_group_methods(&self) -> Vec { + let group_methods = self.group_methods(); + group_methods + .iter() + .map(|group_method| group_method.generate_method()) + .collect() + } - impl #auth { - #group_method + fn group_factory(&self) -> TokenStream { + let struct_name = self.struct_name(); + let name_snake = self.name_snake(); + let auth = auth_ident(); + + util::add_docs( + &self.description, + quote! { + impl super::#auth { + pub fn #name_snake(&self) -> #struct_name { + #struct_name::new(self) + } + } + }, + ) + } + + fn group_struct(&self) -> TokenStream { + let struct_name = self.struct_name(); + let auth = auth_ident(); + + quote! { + #[derive(Debug)] + pub struct #struct_name<'a> { + auth: &'a super::#auth, + } + } + } + + fn group_methods(&self) -> Vec { + self.methods + .iter() + .map(|method| GroupMethod::new(self, method)) + .collect() + } + + fn struct_name(&self) -> Ident { + self.name_camel() + } + + fn name_camel(&self) -> Ident { + util::to_ident(&self.name.to_camel()) + } + + fn name_snake(&self) -> Ident { + util::to_ident(&self.name.to_snake()) + } +} + +impl parser::ApiMethod { + fn structs(&self) -> TokenStream { + let objects = self.types.objects(); + let structs = objects.iter().map(|obj| obj.generate_struct()); + + quote! { + #(#structs)* + } + } + + fn enums(&self) -> TokenStream { + let enums = self.types.enums(); + let generated_enums = enums.iter().map(|e| e.generate()); + + quote! { + #(#generated_enums)* + } + } + + fn name_camel(&self) -> Ident { + util::to_ident(&self.name.to_camel()) + } + + fn name_snake(&self) -> Ident { + util::to_ident(&self.name.to_snake()) + } +} + +impl parser::TypeWithName { + fn generate_struct(&self) -> TokenStream { + let fields = self.types.iter().map(|obj| obj.generate_struct_field()); + let name = util::to_ident(&self.name); + + quote! { + #[derive(Debug, serde::Deserialize)] + pub struct #name { + #(#fields,)* + } + } + } +} + +impl types::Type { + fn generate_struct_field(&self) -> TokenStream { + let name_snake = self.name_snake(); + let type_name = util::to_ident(&self.to_owned_type()); + let orig_name = self.name(); + + util::add_docs( + &self.get_type_info().description, + quote! { + #[serde(rename = #orig_name)] + #name_snake: #type_name + }, + ) + } + + fn name(&self) -> String { + self.get_type_info().name.clone() + } + + fn name_camel(&self) -> Ident { + util::to_ident(&self.name().to_camel()) + } + + fn name_snake(&self) -> Ident { + util::to_ident(&self.name().to_snake()) + } +} + +impl parser::Enum { + fn generate(&self) -> TokenStream { + let values = self.values.iter().map(|enum_value| enum_value.generate()); + let name = util::to_ident(&self.name); + + quote! { + #[allow(clippy::enum_variant_names)] + #[derive(Debug, serde::Deserialize, PartialEq, Eq)] + pub enum #name { + #(#values,)* + } + } + } +} + +impl parser::EnumValue { + fn generate(&self) -> TokenStream { + util::add_docs(&self.description, self.generate_field()) + } + + fn generate_field(&self) -> TokenStream { + let orig_name = self.original_value.clone(); + + // special enum value which does not follow conventions + if orig_name == "\"/path/to/download/to\"" { + quote! { + PathToDownloadTo(String) + } + } else { + let name_camel = self.name_camel(); + quote! { + #[serde(rename = #orig_name)] + #name_camel + } + } + } + + fn name_camel(&self) -> Ident { + util::to_ident(&self.value.to_camel()) + } + + fn name_snake(&self) -> Ident { + util::to_ident(&self.value.to_snake()) + } +} + +#[derive(Debug)] +struct GroupMethod<'a> { + group: &'a parser::ApiGroup, + method: &'a parser::ApiMethod, +} + +impl<'a> GroupMethod<'a> { + fn new(group: &'a parser::ApiGroup, method: &'a parser::ApiMethod) -> Self { + Self { group, method } + } + + fn generate_response_struct(&self) -> TokenStream { + let response = match self.method.types.response() { + Some(res) => res, + None => return quote! {}, + }; + + let struct_fields = response.iter().map(|field| field.generate_struct_field()); + + quote! { + #[derive(Debug, serde::Deserialize)] + pub struct Response { + #(#struct_fields,)* + } + } + } + + fn generate_optional_builder(&self) -> TokenStream { + let optional_params = match self.method.types.optional_parameters() { + Some(params) => params, + None => return quote! {}, + }; + + let builder_methods = optional_params + .iter() + .map(|param| param.generate_optional_builder_method_with_docs()); + + let group_name = self.group.struct_name(); + let mandatory_params = self.mandatory_parameters(); + let mandatory_param_form_builder = self.mandatory_parameters_as_form_builder(); + let send_method = self.generate_optional_builder_send_method(); + + quote! { + pub struct Builder<'a> { + group: &'a super::#group_name<'a>, + form: reqwest::multipart::Form, + } + + impl<'a> Builder<'a> { + pub fn new(group: &'a super::#group_name, #mandatory_params) -> Self { + let form = reqwest::multipart::Form::new(); + #mandatory_param_form_builder + Self { group, form } + } + + #send_method + + #(#builder_methods)* + } + } + } + + fn generate_optional_builder_send_method(&self) -> TokenStream { + let method_url = format!("/api/v2/{}/{}", self.group.url, self.method.url); + + match self.method.types.response() { + Some(_) => { + quote! { + pub async fn send(self) -> super::super::Result { + let res = self + .group + .auth + .authenticated_client(#method_url) + .multipart(self.form) + .send() + .await? + .json::() + .await?; + + Ok(res) + } + } + } + None => { + quote! { + pub async fn send(self) -> super::super::Result { + let res = self + .group + .auth + .authenticated_client(#method_url) + .multipart(self.form) + .send() + .await? + .text() + .await?; + + Ok(res) + } + } + } + } + } + + fn mandatory_parameters(&self) -> TokenStream { + let mandatory_params = match self.method.types.mandatory_params() { + Some(p) => p, + None => return quote! {}, + }; + + let params = mandatory_params.iter().map(|param| param.to_parameter()); + + quote! { + #(#params),* + } + } + + fn mandatory_parameters_as_form_builder(&self) -> TokenStream { + let mandatory_params = match self.method.types.mandatory_params() { + Some(p) => p, + None => return quote! {}, + }; + + let builder = mandatory_params + .iter() + .map(|param| param.generate_form_builder(quote! { form })); + + quote! { + #(let #builder)* + } + } + + fn generate_method(&self) -> TokenStream { + let method_name = self.method.name_snake(); + let structs = self.method.structs(); + let enums = self.method.enums(); + let builder = self.generate_optional_builder(); + let response_struct = self.generate_response_struct(); + + quote! { + pub mod #method_name { + #structs + #enums + #builder + #response_struct + } + } + } +} + +impl types::Type { + fn generate_optional_builder_method_with_docs(&self) -> TokenStream { + util::add_docs( + &self.get_type_info().description, + self.generate_optional_builder_method(), + ) + } + + fn borrowed_type_ident(&self) -> Ident { + util::to_ident(&self.to_borrowed_type()) + } + + fn to_parameter(&self) -> TokenStream { + let name_snake = self.name_snake(); + let borrowed_type = self.borrowed_type(); + + quote! { #name_snake: #borrowed_type } + } + + fn generate_form_builder(&self, add_to: TokenStream) -> TokenStream { + let name_str = self.name(); + let name_snake = self.name_snake(); + + quote! { + #add_to = #add_to.text(#name_str, #name_snake.to_string()); + } + } + + fn generate_optional_builder_method(&self) -> TokenStream { + let name_snake = self.name_snake(); + let borrowed_type = self.borrowed_type(); + let form_builder = self.generate_form_builder(quote! { self.form }); + + quote! { + pub fn #name_snake(mut self, #name_snake: #borrowed_type) -> Self { + #form_builder; + self + } + } + } + + fn borrowed_type(&self) -> TokenStream { + if self.should_borrow() { + let type_ = self.borrowed_type_ident(); + quote! { &#type_ } + } else { + let type_ = self.borrowed_type_ident(); + quote! { #type_ } } } } diff --git a/qbittorrent-web-api-gen/src/generate/skeleton.rs b/qbittorrent-web-api-gen/src/generate/skeleton.rs index fb74c23..e09f91b 100644 --- a/qbittorrent-web-api-gen/src/generate/skeleton.rs +++ b/qbittorrent-web-api-gen/src/generate/skeleton.rs @@ -10,13 +10,7 @@ pub fn generate_skeleton(ident: &syn::Ident) -> proc_macro2::TokenStream { let auth = auth_ident(); quote! { - use reqwest::RequestBuilder; - use serde::Deserialize; - use thiserror::Error; - - use super::#ident; - - impl #ident { + impl super::#ident { /// Creates an authenticated client. /// base_url is the url to the qbittorrent instance, i.e. http://localhost:8080 pub async fn login( @@ -61,7 +55,7 @@ pub fn generate_skeleton(ident: &syn::Ident) -> proc_macro2::TokenStream { } #[allow(clippy::enum_variant_names)] - #[derive(Debug, Error)] + #[derive(Debug, thiserror::Error)] pub enum Error { #[error("failed to parse auth cookie")] AuthCookieParseError, @@ -81,7 +75,7 @@ pub fn generate_skeleton(ident: &syn::Ident) -> proc_macro2::TokenStream { } impl #auth { - fn authenticated_client(&self, url: &str) -> RequestBuilder { + fn authenticated_client(&self, url: &str) -> reqwest::RequestBuilder { let url = format!("{}{}", self.base_url, url); let cookie = self.auth_cookie.clone(); diff --git a/qbittorrent-web-api-gen/src/parser/group/method/method_tests/enum.check b/qbittorrent-web-api-gen/src/parser/group/method/method_tests/enum.check new file mode 100644 index 0000000..165730d --- /dev/null +++ b/qbittorrent-web-api-gen/src/parser/group/method/method_tests/enum.check @@ -0,0 +1,37 @@ +ApiMethod { + name: "foo", + description: None, + url: "foo", + types: CompositeTypes { + composite_types: [ + Enum( + Enum { + name: "ScanDirs", + values: [ + EnumValue { + description: Some( + "Download to the monitored folder", + ), + value: "DownloadToTheMonitoredFolder", + original_value: "0", + }, + EnumValue { + description: Some( + "Download to the default save path", + ), + value: "DownloadToTheDefaultSavePath", + original_value: "1", + }, + EnumValue { + description: Some( + "Download to this path", + ), + value: "\"/path/to/download/to\"", + original_value: "\"/path/to/download/to\"", + }, + ], + }, + ), + ], + }, +} \ No newline at end of file diff --git a/qbittorrent-web-api-gen/src/parser/group/method/method_tests/enum.md b/qbittorrent-web-api-gen/src/parser/group/method/method_tests/enum.md new file mode 100644 index 0000000..75f74c6 --- /dev/null +++ b/qbittorrent-web-api-gen/src/parser/group/method/method_tests/enum.md @@ -0,0 +1,12 @@ +## Testing + +Name: `foo` + +Possible values of `scan_dirs`: + +Value | Description +----------------------------|------------ +`0` | Download to the monitored folder +`1` | Download to the default save path +`"/path/to/download/to"` | Download to this path + diff --git a/qbittorrent-web-api-gen/src/parser/group/method/method_tests/enum.tree b/qbittorrent-web-api-gen/src/parser/group/method/method_tests/enum.tree new file mode 100644 index 0000000..6a8f814 --- /dev/null +++ b/qbittorrent-web-api-gen/src/parser/group/method/method_tests/enum.tree @@ -0,0 +1,67 @@ +TokenTree { + title: None, + content: [], + children: [ + TokenTree { + title: Some( + "Testing", + ), + content: [ + Text( + "", + ), + Text( + "Name: `foo`", + ), + Text( + "", + ), + Text( + "Possible values of `scan_dirs`:", + ), + Text( + "", + ), + Table( + Table { + header: TableRow { + raw: "Value | Description", + columns: [ + "Value", + "Description", + ], + }, + split: "----------------------------|------------", + rows: [ + TableRow { + raw: "`0` | Download to the monitored folder", + columns: [ + "0", + "Download to the monitored folder", + ], + }, + TableRow { + raw: "`1` | Download to the default save path", + columns: [ + "1", + "Download to the default save path", + ], + }, + TableRow { + raw: "`\"/path/to/download/to\"` | Download to this path", + columns: [ + "\"/path/to/download/to\"", + "Download to this path", + ], + }, + ], + }, + ), + Text( + "", + ), + ], + children: [], + }, + ], +} \ No newline at end of file diff --git a/qbittorrent-web-api-gen/src/parser/group/method/method_tests/search_result.check b/qbittorrent-web-api-gen/src/parser/group/method/method_tests/search_result.check index 5609adf..72dd726 100644 --- a/qbittorrent-web-api-gen/src/parser/group/method/method_tests/search_result.check +++ b/qbittorrent-web-api-gen/src/parser/group/method/method_tests/search_result.check @@ -3,98 +3,174 @@ ApiMethod { description: Some( "The response is a JSON object with the following fields\n\n\n\n\nExample:\n\n```JSON\n{\n \"results\": [\n {\n \"descrLink\": \"http://www.legittorrents.info/index.php?page=torrent-details&id=8d5f512e1acb687029b8d7cc6c5a84dce51d7a41\",\n \"fileName\": \"Ubuntu-10.04-32bit-NeTV.ova\",\n \"fileSize\": -1,\n \"fileUrl\": \"http://www.legittorrents.info/download.php?id=8d5f512e1acb687029b8d7cc6c5a84dce51d7a41&f=Ubuntu-10.04-32bit-NeTV.ova.torrent\",\n \"nbLeechers\": 1,\n \"nbSeeders\": 0,\n \"siteUrl\": \"http://www.legittorrents.info\"\n },\n {\n \"descrLink\": \"http://www.legittorrents.info/index.php?page=torrent-details&id=d5179f53e105dc2c2401bcfaa0c2c4936a6aa475\",\n \"fileName\": \"mangOH-Legato-17_06-Ubuntu-16_04.ova\",\n \"fileSize\": -1,\n \"fileUrl\": \"http://www.legittorrents.info/download.php?id=d5179f53e105dc2c2401bcfaa0c2c4936a6aa475&f=mangOH-Legato-17_06-Ubuntu-16_04.ova.torrent\",\n \"nbLeechers\": 0,\n \"nbSeeders\": 59,\n \"siteUrl\": \"http://www.legittorrents.info\"\n }\n ],\n \"status\": \"Running\",\n \"total\": 2\n}\n```", ), - parameters: Some( - ApiParameters { - mandatory: [ - Number( - TypeInfo { - name: "id", - is_optional: false, - is_list: false, - description: Some( - "ID of the search job", - ), - type_description: None, - }, - ), - ], - optional: [ - Number( - TypeInfo { - name: "limit", - is_optional: true, - is_list: false, - description: Some( - "max number of results to return. 0 or negative means no limit", - ), - type_description: None, - }, - ), - Number( - TypeInfo { - name: "offset", - is_optional: true, - is_list: false, - description: Some( - "result to start at. A negative number means count backwards (e.g. -2 returns the 2 most recent results)", - ), - type_description: None, - }, - ), - ], - }, - ), - return_type: Some( - ReturnType { - is_list: false, - parameters: [ - ReturnTypeParameter { - name: "results", - description: "Array of result objects- see table below", - return_type: StringArray( - TypeInfo { - name: "results", - is_optional: false, - is_list: false, - description: Some( - "Array of result objects- see table below", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "status", - description: "Current status of the search job (either Running or Stopped)", - return_type: String( - TypeInfo { - name: "status", - is_optional: false, - is_list: false, - description: Some( - "Current status of the search job (either Running or Stopped)", - ), - type_description: None, - }, - ), - }, - ReturnTypeParameter { - name: "total", - description: "Total number of results. If the status is Running this number may continue to increase", - return_type: Number( - TypeInfo { - name: "total", - is_optional: false, - is_list: false, - description: Some( - "Total number of results. If the status is Running this number may continue to increase", - ), - type_description: None, - }, - ), - }, - ], - }, - ), url: "results", + types: CompositeTypes { + composite_types: [ + Parameters( + TypeWithoutName { + types: [ + Number( + TypeInfo { + name: "id", + is_optional: false, + is_list: false, + description: Some( + "ID of the search job", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "limit", + is_optional: true, + is_list: false, + description: Some( + "max number of results to return. 0 or negative means no limit", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "offset", + is_optional: true, + is_list: false, + description: Some( + "result to start at. A negative number means count backwards (e.g. -2 returns the 2 most recent results)", + ), + type_description: None, + }, + ), + ], + }, + ), + Object( + TypeWithName { + name: "Result", + types: [ + String( + TypeInfo { + name: "descrLink", + is_optional: false, + is_list: false, + description: Some( + "URL of the torrent's description page", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "fileName", + is_optional: false, + is_list: false, + description: Some( + "Name of the file", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "fileSize", + is_optional: false, + is_list: false, + description: Some( + "Size of the file in Bytes", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "fileUrl", + is_optional: false, + is_list: false, + description: Some( + "Torrent download link (usually either .torrent file or magnet link)", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "nbLeechers", + is_optional: false, + is_list: false, + description: Some( + "Number of leechers", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "nbSeeders", + is_optional: false, + is_list: false, + description: Some( + "Number of seeders", + ), + type_description: None, + }, + ), + String( + TypeInfo { + name: "siteUrl", + is_optional: false, + is_list: false, + description: Some( + "URL of the torrent site", + ), + type_description: None, + }, + ), + ], + }, + ), + Response( + TypeWithoutName { + types: [ + Object( + Object { + type_info: TypeInfo { + name: "results", + is_optional: false, + is_list: false, + description: Some( + "Array of result objects- see table below", + ), + type_description: None, + }, + ref_type: "Result", + }, + ), + String( + TypeInfo { + name: "status", + is_optional: false, + is_list: false, + description: Some( + "Current status of the search job (either Running or Stopped)", + ), + type_description: None, + }, + ), + Number( + TypeInfo { + name: "total", + is_optional: false, + is_list: false, + description: Some( + "Total number of results. If the status is Running this number may continue to increase", + ), + type_description: None, + }, + ), + ], + }, + ), + ], + }, } \ No newline at end of file diff --git a/qbittorrent-web-api-gen/src/parser/group/method/mod.rs b/qbittorrent-web-api-gen/src/parser/group/method/mod.rs index 1099227..5f03a1a 100644 --- a/qbittorrent-web-api-gen/src/parser/group/method/mod.rs +++ b/qbittorrent-web-api-gen/src/parser/group/method/mod.rs @@ -1,18 +1,75 @@ mod description; -mod return_type; +// mod return_type; mod url; use crate::{md_parser, types}; -pub use return_type::ReturnType; -use std::collections::HashMap; +use case::CaseExt; +use regex::Regex; +use std::collections::{BTreeMap, HashMap}; #[derive(Debug)] pub struct ApiMethod { pub name: String, pub description: Option, - pub parameters: Option, - pub return_type: Option, pub url: String, + pub types: CompositeTypes, +} + +#[derive(Debug)] +pub struct CompositeTypes { + pub composite_types: Vec, +} + +impl CompositeTypes { + pub fn new(tables: &Tables) -> Self { + Self { + composite_types: tables.get_all_tables_as_types(), + } + } + + pub fn parameters(&self) -> Option<&Vec> { + self.composite_types.iter().find_map(|type_| match type_ { + CompositeType::Parameters(p) => Some(&p.types), + _ => None, + }) + } + + pub fn optional_parameters(&self) -> Option> { + self.parameters() + .map(|params| params.iter().filter(|param| param.is_optional()).collect()) + } + + pub fn mandatory_params(&self) -> Option> { + self.parameters() + .map(|params| params.iter().filter(|param| !param.is_optional()).collect()) + } + + pub fn response(&self) -> Option<&Vec> { + self.composite_types.iter().find_map(|type_| match type_ { + CompositeType::Response(p) => Some(&p.types), + _ => None, + }) + } + + pub fn objects(&self) -> Vec<&TypeWithName> { + self.composite_types + .iter() + .filter_map(|type_| match type_ { + CompositeType::Object(p) => Some(p), + _ => None, + }) + .collect() + } + + pub fn enums(&self) -> Vec<&Enum> { + self.composite_types + .iter() + .filter_map(|type_| match type_ { + CompositeType::Enum(p) => Some(p), + _ => None, + }) + .collect() + } } #[derive(Debug)] @@ -21,24 +78,86 @@ pub struct ApiParameters { pub optional: Vec, } -impl ApiParameters { - fn new(params: Vec) -> Self { - let (mandatory, optional) = params.into_iter().fold( - (vec![], vec![]), - |(mut mandatory, mut optional), parameter| { - if parameter.get_type_info().is_optional { - optional.push(parameter); - } else { - mandatory.push(parameter); - } +#[derive(Debug)] +pub enum CompositeType { + Enum(Enum), + Object(TypeWithName), + Response(TypeWithoutName), + Parameters(TypeWithoutName), +} - (mandatory, optional) - }, - ); +#[derive(Debug)] +pub struct TypeWithName { + pub name: String, + pub types: Vec, +} +#[derive(Debug)] +pub struct TypeWithoutName { + pub types: Vec, +} + +impl TypeWithoutName { + pub fn new(types: Vec) -> Self { + Self { types } + } +} + +impl TypeWithName { + pub fn new(name: &str, types: Vec) -> Self { Self { - mandatory, - optional, + name: name.to_string(), + types, + } + } +} + +#[derive(Debug)] +pub struct Enum { + pub name: String, + pub values: Vec, +} + +#[derive(Debug)] +pub struct EnumValue { + pub description: Option, + pub value: String, + pub original_value: String, +} + +impl Enum { + fn new(name: &str, table: &md_parser::Table) -> Self { + let values = table.rows.iter().map(EnumValue::from).collect(); + + Enum { + name: name.to_string(), + values, + } + } +} + +impl From<&md_parser::TableRow> for EnumValue { + fn from(row: &md_parser::TableRow) -> Self { + let description = row.columns.get(1).cloned(); + let original_value = row.columns[0].clone(); + let value = if original_value.parse::().is_ok() { + let name = description + .clone() + .unwrap() + .replace(' ', "_") + .replace('-', "_") + .replace(',', "_"); + + let re = Regex::new(r#"\(.*\)"#).unwrap(); + re.replace_all(&name, "").to_camel() + } else { + original_value.to_camel() + }; + + EnumValue { + description, + value, + original_value, } } } @@ -56,19 +175,13 @@ impl ApiMethod { fn new(child: &md_parser::TokenTree, name: &str) -> Self { let tables = Tables::from(child); let method_description = child.parse_method_description(); - let return_type = child.parse_return_type(); - // let return_type = tables.return_type().map(|r| ReturnType::new(r)); - let parameters = tables - .get_type_containing("Parameters") - .map(ApiParameters::new); let method_url = child.get_method_url(); ApiMethod { name: name.to_string(), description: method_description, - parameters, - return_type, url: method_url, + types: CompositeTypes::new(&tables), } } } @@ -86,7 +199,7 @@ impl md_parser::TokenTree { impl<'a> From<&'a md_parser::TokenTree> for Tables<'a> { fn from(token_tree: &'a md_parser::TokenTree) -> Self { - let mut tables = HashMap::new(); + let mut tables = BTreeMap::new(); let mut prev_prev: Option<&md_parser::MdContent> = None; let mut prev: Option<&md_parser::MdContent> = None; @@ -110,28 +223,80 @@ impl<'a> From<&'a md_parser::TokenTree> for Tables<'a> { } #[derive(Debug)] -struct Tables<'a> { - tables: HashMap, +pub struct Tables<'a> { + tables: BTreeMap, +} + +impl md_parser::Table { + fn to_enum(&self, input_name: &str) -> Option { + let re = Regex::new(r"^Possible values of `(\w+)`$").unwrap(); + + if !re.is_match(input_name) { + return None; + } + + Some(CompositeType::Enum(Enum::new( + &Self::regex_to_name(&re, input_name), + self, + ))) + } + + fn to_object(&self, input_name: &str) -> Option { + let re = Regex::new(r"^(\w+) object$").unwrap(); + + if !re.is_match(input_name) { + return None; + } + + Some(CompositeType::Object(TypeWithName::new( + &Self::regex_to_name(&re, input_name), + self.to_types(), + ))) + } + + fn to_response(&self, input_name: &str) -> Option { + if !input_name.starts_with("The response is a") { + return None; + } + + Some(CompositeType::Response(TypeWithoutName::new( + self.to_types(), + ))) + } + + fn to_parameters(&self, input_name: &str) -> Option { + if !input_name.starts_with("Parameters") { + return None; + } + + Some(CompositeType::Parameters(TypeWithoutName::new( + self.to_types(), + ))) + } + + fn to_composite_type(&self, input_name: &str) -> Option { + self.to_enum(input_name) + .or_else(|| self.to_response(input_name)) + .or_else(|| self.to_object(input_name)) + .or_else(|| self.to_parameters(input_name)) + } + + fn regex_to_name(re: &Regex, input_name: &str) -> String { + re.captures(input_name) + .unwrap() + .get(1) + .unwrap() + .as_str() + .to_string() + .to_camel() + } } impl<'a> Tables<'a> { - fn get_type_containing(&self, name: &str) -> Option> { - self.get_type_containing_as_table(name) - .map(|table| table.to_types()) - } - - fn get_type_containing_as_table(&self, name: &str) -> Option<&md_parser::Table> { - self.get_all_type_containing_as_table(name) - .iter() - .map(|(_, table)| *table) - .find(|_| true) - } - - fn get_all_type_containing_as_table(&self, name: &str) -> HashMap { + fn get_all_tables_as_types(&self) -> Vec { self.tables .iter() - .filter(|(key, _)| key.contains(name)) - .map(|(k, table)| (k.clone(), *table)) + .flat_map(|(k, v)| v.to_composite_type(k)) .collect() } } @@ -207,8 +372,8 @@ mod tests { use std::path::Path; let input = include_str!(concat!(TEST_DIR!(), "/", $test_file, ".md")); - let tree = ApiMethod::try_new(input); - let api_method = parse_api_method(&tree.children[0]).unwrap(); + let tree = TokenTreeFactory::create(input); + let api_method = ApiMethod::try_new(&tree.children[0]).unwrap(); let tree_as_str = format!("{tree:#?}"); let api_method_as_str = format!("{api_method:#?}"); @@ -242,4 +407,9 @@ mod tests { fn search_result() { run_test!("search_result"); } + + #[test] + fn enum_test() { + run_test!("enum"); + } } diff --git a/qbittorrent-web-api-gen/src/types.rs b/qbittorrent-web-api-gen/src/types.rs index d56f58b..b216cc2 100644 --- a/qbittorrent-web-api-gen/src/types.rs +++ b/qbittorrent-web-api-gen/src/types.rs @@ -1,5 +1,8 @@ use std::collections::HashMap; +use case::CaseExt; +use regex::RegexBuilder; + #[derive(Debug, Clone)] pub struct TypeDescriptions { pub value: String, @@ -39,15 +42,22 @@ impl TypeInfo { } #[derive(Debug, Clone)] -pub struct TypeWithRef { +pub struct Object { pub type_info: TypeInfo, pub ref_type: String, } #[derive(Debug, Clone)] -pub struct ComplexObject { +pub struct Enum { pub type_info: TypeInfo, - pub fields: Vec, + pub values: Vec, +} + +#[derive(Debug, Clone)] +pub struct EnumValue { + pub description: Option, + pub key: String, + pub value: String, } pub const OPTIONAL: &str = "_optional_"; @@ -59,8 +69,7 @@ pub enum Type { Bool(TypeInfo), String(TypeInfo), StringArray(TypeInfo), - Object(TypeInfo), - // ComplexObject(ComplexObject), + Object(Object), } impl Type { @@ -72,7 +81,6 @@ impl Type { Type::String(_) => "String".into(), Type::StringArray(_) => "String".into(), Type::Object(_) => "String".into(), - // Type::ComplexObject(_) => panic!("Not implemented for ComplexObject"), } } @@ -88,7 +96,6 @@ impl Type { Type::String(_) => "str".into(), Type::StringArray(_) => "&[str]".into(), Type::Object(_) => "str".into(), - // Type::ComplexObject(_) => panic!("Not implemented for ComplexObject"), } } @@ -96,6 +103,10 @@ impl Type { matches!(self, Type::String(_) | Type::Object(_)) } + pub fn is_optional(&self) -> bool { + self.get_type_info().is_optional + } + pub fn get_type_info(&self) -> &TypeInfo { match self { Type::Number(t) => t, @@ -103,8 +114,7 @@ impl Type { Type::Bool(t) => t, Type::String(t) => t, Type::StringArray(t) => t, - Type::Object(t) => t, - // Type::ComplexObject(ComplexObject { type_info, .. }) => type_info, + Type::Object(t) => &t.type_info, } } @@ -132,46 +142,54 @@ impl Type { ) }; + let create_object_type = |name: &str| { + Some(Type::Object(Object { + type_info: create_type_info(), + ref_type: name.to_camel(), + })) + }; + match type_as_str { "bool" => Some(Type::Bool(create_type_info())), "integer" | "number" | "int" => Some(Type::Number(create_type_info())), "string" => Some(Type::String(create_type_info())), - "array" => Some(Type::StringArray(create_type_info())), - // "array" => description - // .clone() - // .and_then(|ref desc| get_ref_type(desc)) - // .map(|ref_type| { - // Type::ObjectArray(TypeWithRef { - // type_info: create_type_info(), - // ref_type, - // }) - // }) - // .or_else(|| Some(Type::StringArray(create_type_info()))), - "object" => Some(Type::Object(create_type_info())), + "array" => description + .extract_type() + .and_then(|t| create_object_type(&t)) + .or_else(|| Some(Type::StringArray(create_type_info()))), "float" => Some(Type::Float(create_type_info())), - _ => None, + name => create_object_type(name), } } } -// fn get_ref_type(desc: &str) -> Option { -// let re = RegexBuilder::new(r".*array of (\w+)\s?.*") -// .case_insensitive(true) -// .build() -// .unwrap(); +trait ExtractType { + fn extract_type(&self) -> Option; +} -// re.captures(desc) -// .and_then(|captures| captures.get(1)) -// .map(|m| m.as_str().to_owned()) -// } +impl ExtractType for Option { + fn extract_type(&self) -> Option { + self.as_ref().and_then(|t| { + let re = RegexBuilder::new(r".*Array of (\w+) objects.*") + .case_insensitive(true) + .build() + .unwrap(); + + let cap = re.captures(t)?; + + cap.get(1).map(|m| m.as_str().to_camel()) + }) + } +} #[cfg(test)] mod tests { - // use super::*; + use super::*; - // #[test] - // fn should_parse_object_array() { - // let ref_type = get_ref_type("Array of result objects- see table below"); - // assert_eq!("result", ref_type.unwrap()); - // } + #[test] + fn test_regex() { + let input = Some("Array of result objects- see table below".to_string()); + let res = input.extract_type(); + assert_eq!(res.unwrap(), "Result"); + } } diff --git a/qbittorrent-web-api-gen/tests/search_types.rs b/qbittorrent-web-api-gen/tests/search_types.rs index f4000e0..efd57a2 100644 --- a/qbittorrent-web-api-gen/tests/search_types.rs +++ b/qbittorrent-web-api-gen/tests/search_types.rs @@ -11,10 +11,11 @@ struct Api {} async fn main() -> Result<()> { let api = Api::login(BASE_URL, USERNAME, PASSWORD).await?; - let _ = api.search().plugins().await?; - let _ = api.search().results(1).send().await?; - let _ = api.search().delete(1).await?; let _ = api.search().install_plugin("https://raw.githubusercontent.com/qbittorrent/search-plugins/master/nova3/engines/legittorrents.py").await?; + let plugins = api.search().plugins().await?; + eprintln!("{:?}", plugins); + // let _ = api.search().results(1).send().await?; + // let _ = api.search().delete(1).await?; Ok(()) } From 07e825bcd405b9e5ae1542cc3378a47a61cfe84d Mon Sep 17 00:00:00 2001 From: Joel Wachsler Date: Fri, 22 Jul 2022 14:34:47 +0000 Subject: [PATCH 40/47] Fix warnings --- qbittorrent-web-api-gen/groups.txt | 396 ------------------ .../src/generate/group/mod.rs | 12 - .../method/method_tests/search_result.check | 26 -- .../src/parser/group/method/mod.rs | 13 +- qbittorrent-web-api-gen/src/types.rs | 40 +- 5 files changed, 11 insertions(+), 476 deletions(-) diff --git a/qbittorrent-web-api-gen/groups.txt b/qbittorrent-web-api-gen/groups.txt index 4984ab4..7e19da5 100644 --- a/qbittorrent-web-api-gen/groups.txt +++ b/qbittorrent-web-api-gen/groups.txt @@ -17,22 +17,18 @@ TypeInfo { name: "username", is_optional: false, - is_list: false, description: Some( "Username used to access the WebUI", ), - type_description: None, }, ), String( TypeInfo { name: "password", is_optional: false, - is_list: false, description: Some( "Password used to access the WebUI", ), - type_description: None, }, ), ], @@ -93,55 +89,45 @@ TypeInfo { name: "qt", is_optional: false, - is_list: false, description: Some( "QT version", ), - type_description: None, }, ), String( TypeInfo { name: "libtorrent", is_optional: false, - is_list: false, description: Some( "libtorrent version", ), - type_description: None, }, ), String( TypeInfo { name: "boost", is_optional: false, - is_list: false, description: Some( "Boost version", ), - type_description: None, }, ), String( TypeInfo { name: "openssl", is_optional: false, - is_list: false, description: Some( "OpenSSL version", ), - type_description: None, }, ), Number( TypeInfo { name: "bitness", is_optional: false, - is_list: false, description: Some( "Application bitness (e.g. 64-bit)", ), - type_description: None, }, ), ], @@ -535,55 +521,45 @@ TypeInfo { name: "normal", is_optional: true, - is_list: false, description: Some( "Include normal messages (default: true)", ), - type_description: None, }, ), Bool( TypeInfo { name: "info", is_optional: true, - is_list: false, description: Some( "Include info messages (default: true)", ), - type_description: None, }, ), Bool( TypeInfo { name: "warning", is_optional: true, - is_list: false, description: Some( "Include warning messages (default: true)", ), - type_description: None, }, ), Bool( TypeInfo { name: "critical", is_optional: true, - is_list: false, description: Some( "Include critical messages (default: true)", ), - type_description: None, }, ), Number( TypeInfo { name: "last_known_id", is_optional: true, - is_list: false, description: Some( "Exclude messages with \"message id\" <= last_known_id (default: -1)", ), - type_description: None, }, ), ], @@ -607,11 +583,9 @@ TypeInfo { name: "last_known_id", is_optional: true, - is_list: false, description: Some( "Exclude messages with \"message id\" <= last_known_id (default: -1)", ), - type_description: None, }, ), ], @@ -644,11 +618,9 @@ TypeInfo { name: "rid", is_optional: false, - is_list: false, description: Some( "Response ID. If not provided, rid=0 will be assumed. If the given rid is different from the one of last server reply, full_update will be true (see the server reply details for more info)", ), - type_description: None, }, ), ], @@ -661,22 +633,18 @@ TypeInfo { name: "rid", is_optional: false, - is_list: false, description: Some( "Response ID", ), - type_description: None, }, ), Bool( TypeInfo { name: "full_update", is_optional: false, - is_list: false, description: Some( "Whether the response contains all the data or partial data", ), - type_description: None, }, ), Object( @@ -684,11 +652,9 @@ type_info: TypeInfo { name: "torrents", is_optional: false, - is_list: false, description: Some( "Property: torrent hash, value: same as [torrent list](#get-torrent-list)", ), - type_description: None, }, ref_type: "Object", }, @@ -697,11 +663,9 @@ TypeInfo { name: "torrents_removed", is_optional: false, - is_list: false, description: Some( "List of hashes of torrents removed since last request", ), - type_description: None, }, ), Object( @@ -709,11 +673,9 @@ type_info: TypeInfo { name: "categories", is_optional: false, - is_list: false, description: Some( "Info for categories added since last request", ), - type_description: None, }, ref_type: "Object", }, @@ -722,33 +684,27 @@ TypeInfo { name: "categories_removed", is_optional: false, - is_list: false, description: Some( "List of categories removed since last request", ), - type_description: None, }, ), StringArray( TypeInfo { name: "tags", is_optional: false, - is_list: false, description: Some( "List of tags added since last request", ), - type_description: None, }, ), StringArray( TypeInfo { name: "tags_removed", is_optional: false, - is_list: false, description: Some( "List of tags removed since last request", ), - type_description: None, }, ), Object( @@ -756,11 +712,9 @@ type_info: TypeInfo { name: "server_state", is_optional: false, - is_list: false, description: Some( "Global transfer info", ), - type_description: None, }, ref_type: "Object", }, @@ -786,22 +740,18 @@ TypeInfo { name: "hash", is_optional: false, - is_list: false, description: Some( "Torrent hash", ), - type_description: None, }, ), Number( TypeInfo { name: "rid", is_optional: false, - is_list: false, description: Some( "Response ID. If not provided, rid=0 will be assumed. If the given rid is different from the one of last server reply, full_update will be true (see the server reply details for more info)", ), - type_description: None, }, ), ], @@ -834,88 +784,72 @@ TypeInfo { name: "dl_info_speed", is_optional: false, - is_list: false, description: Some( "Global download rate (bytes/s)", ), - type_description: None, }, ), Number( TypeInfo { name: "dl_info_data", is_optional: false, - is_list: false, description: Some( "Data downloaded this session (bytes)", ), - type_description: None, }, ), Number( TypeInfo { name: "up_info_speed", is_optional: false, - is_list: false, description: Some( "Global upload rate (bytes/s)", ), - type_description: None, }, ), Number( TypeInfo { name: "up_info_data", is_optional: false, - is_list: false, description: Some( "Data uploaded this session (bytes)", ), - type_description: None, }, ), Number( TypeInfo { name: "dl_rate_limit", is_optional: false, - is_list: false, description: Some( "Download rate limit (bytes/s)", ), - type_description: None, }, ), Number( TypeInfo { name: "up_rate_limit", is_optional: false, - is_list: false, description: Some( "Upload rate limit (bytes/s)", ), - type_description: None, }, ), Number( TypeInfo { name: "dht_nodes", is_optional: false, - is_list: false, description: Some( "DHT nodes connected to", ), - type_description: None, }, ), String( TypeInfo { name: "connection_status", is_optional: false, - is_list: false, description: Some( "Connection status. See possible values here below", ), - type_description: None, }, ), ], @@ -965,11 +899,9 @@ TypeInfo { name: "limit", is_optional: false, - is_list: false, description: Some( "The global download speed limit to set in bytes/second", ), - type_description: None, }, ), ], @@ -1001,11 +933,9 @@ TypeInfo { name: "limit", is_optional: false, - is_list: false, description: Some( "The global upload speed limit to set in bytes/second", ), - type_description: None, }, ), ], @@ -1027,11 +957,9 @@ TypeInfo { name: "peers", is_optional: false, - is_list: false, description: Some( "The peer to ban, or multiple peers separated by a pipe \\", ), - type_description: None, }, ), ], @@ -1064,88 +992,72 @@ TypeInfo { name: "filter", is_optional: true, - is_list: false, description: Some( "Filter torrent list by state. Allowed state filters: all, downloading, seeding, completed, paused, active, inactive, resumed, stalled, stalled_uploading, stalled_downloading, errored", ), - type_description: None, }, ), String( TypeInfo { name: "category", is_optional: true, - is_list: false, description: Some( "Get torrents with the given category (empty string means \"without category\"; no \"category\" parameter means \"any category\" <- broken until [#11748](https://github.com/qbittorrent/qBittorrent/issues/11748) is resolved). Remember to URL-encode the category name. For example, My category becomes My%20category", ), - type_description: None, }, ), String( TypeInfo { name: "tag", is_optional: true, - is_list: false, description: Some( "Get torrents with the given tag (empty string means \"without tag\"; no \"tag\" parameter means \"any tag\". Remember to URL-encode the category name. For example, My tag becomes My%20tag", ), - type_description: None, }, ), String( TypeInfo { name: "sort", is_optional: true, - is_list: false, description: Some( "Sort torrents by given key. They can be sorted using any field of the response's JSON array (which are documented below) as the sort key.", ), - type_description: None, }, ), Bool( TypeInfo { name: "reverse", is_optional: true, - is_list: false, description: Some( "Enable reverse sorting. Defaults to false", ), - type_description: None, }, ), Number( TypeInfo { name: "limit", is_optional: true, - is_list: false, description: Some( "Limit the number of torrents returned", ), - type_description: None, }, ), Number( TypeInfo { name: "offset", is_optional: true, - is_list: false, description: Some( "Set offset (if less than 0, offset from end)", ), - type_description: None, }, ), String( TypeInfo { name: "hashes", is_optional: true, - is_list: false, description: Some( "Filter by hashes. Can contain multiple hashes separated by \\", ), - type_description: None, }, ), ], @@ -1298,495 +1210,405 @@ TypeInfo { name: "added_on", is_optional: false, - is_list: false, description: Some( "Time (Unix Epoch) when the torrent was added to the client", ), - type_description: None, }, ), Number( TypeInfo { name: "amount_left", is_optional: false, - is_list: false, description: Some( "Amount of data left to download (bytes)", ), - type_description: None, }, ), Bool( TypeInfo { name: "auto_tmm", is_optional: false, - is_list: false, description: Some( "Whether this torrent is managed by Automatic Torrent Management", ), - type_description: None, }, ), Float( TypeInfo { name: "availability", is_optional: false, - is_list: false, description: Some( "Percentage of file pieces currently available", ), - type_description: None, }, ), String( TypeInfo { name: "category", is_optional: false, - is_list: false, description: Some( "Category of the torrent", ), - type_description: None, }, ), Number( TypeInfo { name: "completed", is_optional: false, - is_list: false, description: Some( "Amount of transfer data completed (bytes)", ), - type_description: None, }, ), Number( TypeInfo { name: "completion_on", is_optional: false, - is_list: false, description: Some( "Time (Unix Epoch) when the torrent completed", ), - type_description: None, }, ), String( TypeInfo { name: "content_path", is_optional: false, - is_list: false, description: Some( "Absolute path of torrent content (root path for multifile torrents, absolute file path for singlefile torrents)", ), - type_description: None, }, ), Number( TypeInfo { name: "dl_limit", is_optional: false, - is_list: false, description: Some( "Torrent download speed limit (bytes/s). -1 if ulimited.", ), - type_description: None, }, ), Number( TypeInfo { name: "dlspeed", is_optional: false, - is_list: false, description: Some( "Torrent download speed (bytes/s)", ), - type_description: None, }, ), Number( TypeInfo { name: "downloaded", is_optional: false, - is_list: false, description: Some( "Amount of data downloaded", ), - type_description: None, }, ), Number( TypeInfo { name: "downloaded_session", is_optional: false, - is_list: false, description: Some( "Amount of data downloaded this session", ), - type_description: None, }, ), Number( TypeInfo { name: "eta", is_optional: false, - is_list: false, description: Some( "Torrent ETA (seconds)", ), - type_description: None, }, ), Bool( TypeInfo { name: "f_l_piece_prio", is_optional: false, - is_list: false, description: Some( "True if first last piece are prioritized", ), - type_description: None, }, ), Bool( TypeInfo { name: "force_start", is_optional: false, - is_list: false, description: Some( "True if force start is enabled for this torrent", ), - type_description: None, }, ), String( TypeInfo { name: "hash", is_optional: false, - is_list: false, description: Some( "Torrent hash", ), - type_description: None, }, ), Number( TypeInfo { name: "last_activity", is_optional: false, - is_list: false, description: Some( "Last time (Unix Epoch) when a chunk was downloaded/uploaded", ), - type_description: None, }, ), String( TypeInfo { name: "magnet_uri", is_optional: false, - is_list: false, description: Some( "Magnet URI corresponding to this torrent", ), - type_description: None, }, ), Float( TypeInfo { name: "max_ratio", is_optional: false, - is_list: false, description: Some( "Maximum share ratio until torrent is stopped from seeding/uploading", ), - type_description: None, }, ), Number( TypeInfo { name: "max_seeding_time", is_optional: false, - is_list: false, description: Some( "Maximum seeding time (seconds) until torrent is stopped from seeding", ), - type_description: None, }, ), String( TypeInfo { name: "name", is_optional: false, - is_list: false, description: Some( "Torrent name", ), - type_description: None, }, ), Number( TypeInfo { name: "num_complete", is_optional: false, - is_list: false, description: Some( "Number of seeds in the swarm", ), - type_description: None, }, ), Number( TypeInfo { name: "num_incomplete", is_optional: false, - is_list: false, description: Some( "Number of leechers in the swarm", ), - type_description: None, }, ), Number( TypeInfo { name: "num_leechs", is_optional: false, - is_list: false, description: Some( "Number of leechers connected to", ), - type_description: None, }, ), Number( TypeInfo { name: "num_seeds", is_optional: false, - is_list: false, description: Some( "Number of seeds connected to", ), - type_description: None, }, ), Number( TypeInfo { name: "priority", is_optional: false, - is_list: false, description: Some( "Torrent priority. Returns -1 if queuing is disabled or torrent is in seed mode", ), - type_description: None, }, ), Float( TypeInfo { name: "progress", is_optional: false, - is_list: false, description: Some( "Torrent progress (percentage/100)", ), - type_description: None, }, ), Float( TypeInfo { name: "ratio", is_optional: false, - is_list: false, description: Some( "Torrent share ratio. Max ratio value: 9999.", ), - type_description: None, }, ), Float( TypeInfo { name: "ratio_limit", is_optional: false, - is_list: false, description: Some( "TODO (what is different from max_ratio?)", ), - type_description: None, }, ), String( TypeInfo { name: "save_path", is_optional: false, - is_list: false, description: Some( "Path where this torrent's data is stored", ), - type_description: None, }, ), Number( TypeInfo { name: "seeding_time", is_optional: false, - is_list: false, description: Some( "Torrent elapsed time while complete (seconds)", ), - type_description: None, }, ), Number( TypeInfo { name: "seeding_time_limit", is_optional: false, - is_list: false, description: Some( "TODO (what is different from max_seeding_time?) seeding_time_limit is a per torrent setting, when Automatic Torrent Management is disabled, furthermore then max_seeding_time is set to seeding_time_limit for this torrent. If Automatic Torrent Management is enabled, the value is -2. And if max_seeding_time is unset it have a default value -1.", ), - type_description: None, }, ), Number( TypeInfo { name: "seen_complete", is_optional: false, - is_list: false, description: Some( "Time (Unix Epoch) when this torrent was last seen complete", ), - type_description: None, }, ), Bool( TypeInfo { name: "seq_dl", is_optional: false, - is_list: false, description: Some( "True if sequential download is enabled", ), - type_description: None, }, ), Number( TypeInfo { name: "size", is_optional: false, - is_list: false, description: Some( "Total size (bytes) of files selected for download", ), - type_description: None, }, ), String( TypeInfo { name: "state", is_optional: false, - is_list: false, description: Some( "Torrent state. See table here below for the possible values", ), - type_description: None, }, ), Bool( TypeInfo { name: "super_seeding", is_optional: false, - is_list: false, description: Some( "True if super seeding is enabled", ), - type_description: None, }, ), String( TypeInfo { name: "tags", is_optional: false, - is_list: false, description: Some( "Comma-concatenated tag list of the torrent", ), - type_description: None, }, ), Number( TypeInfo { name: "time_active", is_optional: false, - is_list: false, description: Some( "Total active time (seconds)", ), - type_description: None, }, ), Number( TypeInfo { name: "total_size", is_optional: false, - is_list: false, description: Some( "Total size (bytes) of all file in this torrent (including unselected ones)", ), - type_description: None, }, ), String( TypeInfo { name: "tracker", is_optional: false, - is_list: false, description: Some( "The first tracker with working status. Returns empty string if no tracker is working.", ), - type_description: None, }, ), Number( TypeInfo { name: "up_limit", is_optional: false, - is_list: false, description: Some( "Torrent upload speed limit (bytes/s). -1 if ulimited.", ), - type_description: None, }, ), Number( TypeInfo { name: "uploaded", is_optional: false, - is_list: false, description: Some( "Amount of data uploaded", ), - type_description: None, }, ), Number( TypeInfo { name: "uploaded_session", is_optional: false, - is_list: false, description: Some( "Amount of data uploaded this session", ), - type_description: None, }, ), Number( TypeInfo { name: "upspeed", is_optional: false, - is_list: false, description: Some( "Torrent upload speed (bytes/s)", ), - type_description: None, }, ), ], @@ -1810,11 +1632,9 @@ TypeInfo { name: "hash", is_optional: false, - is_list: false, description: Some( "The hash of the torrent you want to get the generic properties of", ), - type_description: None, }, ), ], @@ -1838,11 +1658,9 @@ TypeInfo { name: "hash", is_optional: false, - is_list: false, description: Some( "The hash of the torrent you want to get the trackers of", ), - type_description: None, }, ), ], @@ -1897,88 +1715,72 @@ TypeInfo { name: "url", is_optional: false, - is_list: false, description: Some( "Tracker url", ), - type_description: None, }, ), Number( TypeInfo { name: "status", is_optional: false, - is_list: false, description: Some( "Tracker status. See the table below for possible values", ), - type_description: None, }, ), Number( TypeInfo { name: "tier", is_optional: false, - is_list: false, description: Some( "Tracker priority tier. Lower tier trackers are tried before higher tiers. Tier numbers are valid when >= 0, < 0 is used as placeholder when tier does not exist for special entries (such as DHT).", ), - type_description: None, }, ), Number( TypeInfo { name: "num_peers", is_optional: false, - is_list: false, description: Some( "Number of peers for current torrent, as reported by the tracker", ), - type_description: None, }, ), Number( TypeInfo { name: "num_seeds", is_optional: false, - is_list: false, description: Some( "Number of seeds for current torrent, asreported by the tracker", ), - type_description: None, }, ), Number( TypeInfo { name: "num_leeches", is_optional: false, - is_list: false, description: Some( "Number of leeches for current torrent, as reported by the tracker", ), - type_description: None, }, ), Number( TypeInfo { name: "num_downloaded", is_optional: false, - is_list: false, description: Some( "Number of completed downlods for current torrent, as reported by the tracker", ), - type_description: None, }, ), String( TypeInfo { name: "msg", is_optional: false, - is_list: false, description: Some( "Tracker message (there is no way of knowing what this message is - it's up to tracker admins)", ), - type_description: None, }, ), ], @@ -2002,11 +1804,9 @@ TypeInfo { name: "hash", is_optional: false, - is_list: false, description: Some( "The hash of the torrent you want to get the webseeds of", ), - type_description: None, }, ), ], @@ -2019,11 +1819,9 @@ TypeInfo { name: "url", is_optional: false, - is_list: false, description: Some( "URL of the web seed", ), - type_description: None, }, ), ], @@ -2047,22 +1845,18 @@ TypeInfo { name: "hash", is_optional: false, - is_list: false, description: Some( "The hash of the torrent you want to get the contents of", ), - type_description: None, }, ), String( TypeInfo { name: "indexes", is_optional: true, - is_list: false, description: Some( "The indexes of the files you want to retrieve. indexes can contain multiple values separated by \\", ), - type_description: None, }, ), ], @@ -2121,11 +1915,9 @@ TypeInfo { name: "hash", is_optional: false, - is_list: false, description: Some( "The hash of the torrent you want to get the pieces' states of", ), - type_description: None, }, ), ], @@ -2149,11 +1941,9 @@ TypeInfo { name: "hash", is_optional: false, - is_list: false, description: Some( "The hash of the torrent you want to get the pieces' hashes of", ), - type_description: None, }, ), ], @@ -2175,11 +1965,9 @@ TypeInfo { name: "hashes", is_optional: false, - is_list: false, description: Some( "The hashes of the torrents you want to pause. hashes can contain multiple hashes separated by \\", ), - type_description: None, }, ), ], @@ -2201,11 +1989,9 @@ TypeInfo { name: "hashes", is_optional: false, - is_list: false, description: Some( "The hashes of the torrents you want to resume. hashes can contain multiple hashes separated by \\", ), - type_description: None, }, ), ], @@ -2227,11 +2013,9 @@ TypeInfo { name: "hashes", is_optional: false, - is_list: false, description: Some( "The hashes of the torrents you want to delete. hashes can contain multiple hashes separated by \\", ), - type_description: None, }, ), Object( @@ -2239,9 +2023,7 @@ type_info: TypeInfo { name: "deleteFiles", is_optional: false, - is_list: false, description: None, - type_description: None, }, ref_type: "If set to true, the downloaded data will also be deleted, otherwise has no effect.", }, @@ -2265,11 +2047,9 @@ TypeInfo { name: "hashes", is_optional: false, - is_list: false, description: Some( "The hashes of the torrents you want to recheck. hashes can contain multiple hashes separated by \\", ), - type_description: None, }, ), ], @@ -2291,11 +2071,9 @@ TypeInfo { name: "hashes", is_optional: false, - is_list: false, description: Some( "The hashes of the torrents you want to reannounce. hashes can contain multiple hashes separated by \\", ), - type_description: None, }, ), ], @@ -2317,11 +2095,9 @@ TypeInfo { name: "urls", is_optional: false, - is_list: false, description: Some( "URLs separated with newlines", ), - type_description: None, }, ), Object( @@ -2329,11 +2105,9 @@ type_info: TypeInfo { name: "torrents", is_optional: false, - is_list: false, description: Some( "Raw data of torrent file. torrents can be presented multiple times.", ), - type_description: None, }, ref_type: "Raw", }, @@ -2342,165 +2116,135 @@ TypeInfo { name: "savepath", is_optional: true, - is_list: false, description: Some( "Download folder", ), - type_description: None, }, ), String( TypeInfo { name: "cookie", is_optional: true, - is_list: false, description: Some( "Cookie sent to download the .torrent file", ), - type_description: None, }, ), String( TypeInfo { name: "category", is_optional: true, - is_list: false, description: Some( "Category for the torrent", ), - type_description: None, }, ), String( TypeInfo { name: "tags", is_optional: true, - is_list: false, description: Some( "Tags for the torrent, split by ','", ), - type_description: None, }, ), String( TypeInfo { name: "skip_checking", is_optional: true, - is_list: false, description: Some( "Skip hash checking. Possible values are true, false (default)", ), - type_description: None, }, ), String( TypeInfo { name: "paused", is_optional: true, - is_list: false, description: Some( "Add torrents in the paused state. Possible values are true, false (default)", ), - type_description: None, }, ), String( TypeInfo { name: "root_folder", is_optional: true, - is_list: false, description: Some( "Create the root folder. Possible values are true, false, unset (default)", ), - type_description: None, }, ), String( TypeInfo { name: "rename", is_optional: true, - is_list: false, description: Some( "Rename torrent", ), - type_description: None, }, ), Number( TypeInfo { name: "upLimit", is_optional: true, - is_list: false, description: Some( "Set torrent upload speed limit. Unit in bytes/second", ), - type_description: None, }, ), Number( TypeInfo { name: "dlLimit", is_optional: true, - is_list: false, description: Some( "Set torrent download speed limit. Unit in bytes/second", ), - type_description: None, }, ), Float( TypeInfo { name: "ratioLimit", is_optional: true, - is_list: false, description: Some( "Set torrent share ratio limit", ), - type_description: None, }, ), Number( TypeInfo { name: "seedingTimeLimit", is_optional: true, - is_list: false, description: Some( "Set torrent seeding time limit. Unit in seconds", ), - type_description: None, }, ), Bool( TypeInfo { name: "autoTMM", is_optional: true, - is_list: false, description: Some( "Whether Automatic Torrent Management should be used", ), - type_description: None, }, ), String( TypeInfo { name: "sequentialDownload", is_optional: true, - is_list: false, description: Some( "Enable sequential download. Possible values are true, false (default)", ), - type_description: None, }, ), String( TypeInfo { name: "firstLastPiecePrio", is_optional: true, - is_list: false, description: Some( "Prioritize download first last piece. Possible values are true, false (default)", ), - type_description: None, }, ), ], @@ -2530,33 +2274,27 @@ TypeInfo { name: "hash", is_optional: false, - is_list: false, description: Some( "The hash of the torrent", ), - type_description: None, }, ), String( TypeInfo { name: "origUrl", is_optional: false, - is_list: false, description: Some( "The tracker URL you want to edit", ), - type_description: None, }, ), String( TypeInfo { name: "newUrl", is_optional: false, - is_list: false, description: Some( "The new URL to replace the origUrl", ), - type_description: None, }, ), ], @@ -2578,22 +2316,18 @@ TypeInfo { name: "hash", is_optional: false, - is_list: false, description: Some( "The hash of the torrent", ), - type_description: None, }, ), String( TypeInfo { name: "urls", is_optional: false, - is_list: false, description: Some( "URLs to remove, separated by \\", ), - type_description: None, }, ), ], @@ -2615,22 +2349,18 @@ TypeInfo { name: "hashes", is_optional: false, - is_list: false, description: Some( "The hash of the torrent, or multiple hashes separated by a pipe \\", ), - type_description: None, }, ), String( TypeInfo { name: "peers", is_optional: false, - is_list: false, description: Some( "The peer to add, or multiple peers separated by a pipe \\", ), - type_description: None, }, ), ], @@ -2652,11 +2382,9 @@ TypeInfo { name: "hashes", is_optional: false, - is_list: false, description: Some( "The hashes of the torrents you want to increase the priority of. hashes can contain multiple hashes separated by \\", ), - type_description: None, }, ), ], @@ -2678,11 +2406,9 @@ TypeInfo { name: "hashes", is_optional: false, - is_list: false, description: Some( "The hashes of the torrents you want to decrease the priority of. hashes can contain multiple hashes separated by \\", ), - type_description: None, }, ), ], @@ -2704,11 +2430,9 @@ TypeInfo { name: "hashes", is_optional: false, - is_list: false, description: Some( "The hashes of the torrents you want to set to the maximum priority. hashes can contain multiple hashes separated by \\", ), - type_description: None, }, ), ], @@ -2730,11 +2454,9 @@ TypeInfo { name: "hashes", is_optional: false, - is_list: false, description: Some( "The hashes of the torrents you want to set to the minimum priority. hashes can contain multiple hashes separated by \\", ), - type_description: None, }, ), ], @@ -2756,33 +2478,27 @@ TypeInfo { name: "hash", is_optional: false, - is_list: false, description: Some( "The hash of the torrent", ), - type_description: None, }, ), String( TypeInfo { name: "id", is_optional: false, - is_list: false, description: Some( "File ids, separated by \\", ), - type_description: None, }, ), Number( TypeInfo { name: "priority", is_optional: false, - is_list: false, description: Some( "File priority to set (consult [torrent contents API](#get-torrent-contents) for possible values)", ), - type_description: None, }, ), ], @@ -2940,11 +2656,9 @@ TypeInfo { name: "hashes", is_optional: false, - is_list: false, description: Some( "The hashes of the torrents you want to toggle sequential download for. hashes can contain multiple hashes separated by \\", ), - type_description: None, }, ), ], @@ -2966,11 +2680,9 @@ TypeInfo { name: "hashes", is_optional: false, - is_list: false, description: Some( "The hashes of the torrents you want to toggle the first/last piece priority for. hashes can contain multiple hashes separated by \\", ), - type_description: None, }, ), ], @@ -3008,33 +2720,27 @@ TypeInfo { name: "hash", is_optional: false, - is_list: false, description: Some( "The hash of the torrent", ), - type_description: None, }, ), String( TypeInfo { name: "oldPath", is_optional: false, - is_list: false, description: Some( "The old path of the torrent", ), - type_description: None, }, ), String( TypeInfo { name: "newPath", is_optional: false, - is_list: false, description: Some( "The new path to use for the file", ), - type_description: None, }, ), ], @@ -3056,33 +2762,27 @@ TypeInfo { name: "hash", is_optional: false, - is_list: false, description: Some( "The hash of the torrent", ), - type_description: None, }, ), String( TypeInfo { name: "oldPath", is_optional: false, - is_list: false, description: Some( "The old path of the torrent", ), - type_description: None, }, ), String( TypeInfo { name: "newPath", is_optional: false, - is_list: false, description: Some( "The new path to use for the file", ), - type_description: None, }, ), ], @@ -3113,11 +2813,9 @@ TypeInfo { name: "path", is_optional: false, - is_list: false, description: Some( "Full path of added folder (e.g. \"The Pirate Bay\\Top100\")", ), - type_description: None, }, ), ], @@ -3139,22 +2837,18 @@ TypeInfo { name: "url", is_optional: false, - is_list: false, description: Some( "URL of RSS feed (e.g. \"[http://thepiratebay.org/rss//top100/200](http://thepiratebay.org/rss//top100/200)\")", ), - type_description: None, }, ), String( TypeInfo { name: "path", is_optional: true, - is_list: false, description: Some( "Full path of added folder (e.g. \"The Pirate Bay\\Top100\\Video\")", ), - type_description: None, }, ), ], @@ -3176,11 +2870,9 @@ TypeInfo { name: "path", is_optional: false, - is_list: false, description: Some( "Full path of removed item (e.g. \"The Pirate Bay\\Top100\")", ), - type_description: None, }, ), ], @@ -3202,22 +2894,18 @@ TypeInfo { name: "itemPath", is_optional: false, - is_list: false, description: Some( "Current full path of item (e.g. \"The Pirate Bay\\Top100\")", ), - type_description: None, }, ), String( TypeInfo { name: "destPath", is_optional: false, - is_list: false, description: Some( "New full path of item (e.g. \"The Pirate Bay\")", ), - type_description: None, }, ), ], @@ -3239,11 +2927,9 @@ TypeInfo { name: "withData", is_optional: true, - is_list: false, description: Some( "True if you need current feed articles", ), - type_description: None, }, ), ], @@ -3265,22 +2951,18 @@ TypeInfo { name: "itemPath", is_optional: false, - is_list: false, description: Some( "Current full path of item (e.g. \"The Pirate Bay\\Top100\")", ), - type_description: None, }, ), String( TypeInfo { name: "articleId", is_optional: true, - is_list: false, description: Some( "ID of article", ), - type_description: None, }, ), ], @@ -3302,11 +2984,9 @@ TypeInfo { name: "itemPath", is_optional: false, - is_list: false, description: Some( "Current full path of item (e.g. \"The Pirate Bay\\Top100\")", ), - type_description: None, }, ), ], @@ -3328,22 +3008,18 @@ TypeInfo { name: "ruleName", is_optional: false, - is_list: false, description: Some( "Rule name (e.g. \"Punisher\")", ), - type_description: None, }, ), String( TypeInfo { name: "ruleDef", is_optional: false, - is_list: false, description: Some( "JSON encoded rule definition", ), - type_description: None, }, ), ], @@ -3365,22 +3041,18 @@ TypeInfo { name: "ruleName", is_optional: false, - is_list: false, description: Some( "Rule name (e.g. \"Punisher\")", ), - type_description: None, }, ), String( TypeInfo { name: "newRuleName", is_optional: false, - is_list: false, description: Some( "New rule name (e.g. \"The Punisher\")", ), - type_description: None, }, ), ], @@ -3402,11 +3074,9 @@ TypeInfo { name: "ruleName", is_optional: false, - is_list: false, description: Some( "Rule name (e.g. \"Punisher\")", ), - type_description: None, }, ), ], @@ -3455,33 +3125,27 @@ TypeInfo { name: "pattern", is_optional: false, - is_list: false, description: Some( "Pattern to search for (e.g. \"Ubuntu 18.04\")", ), - type_description: None, }, ), String( TypeInfo { name: "plugins", is_optional: false, - is_list: false, description: Some( "Plugins to use for searching (e.g. \"legittorrents\"). Supports multiple plugins separated by \\", ), - type_description: None, }, ), String( TypeInfo { name: "category", is_optional: false, - is_list: false, description: Some( "Categories to limit your search to (e.g. \"legittorrents\"). Available categories depend on the specified plugins. Also supports all", ), - type_description: None, }, ), ], @@ -3494,11 +3158,9 @@ TypeInfo { name: "id", is_optional: false, - is_list: false, description: Some( "ID of the search job", ), - type_description: None, }, ), ], @@ -3520,11 +3182,9 @@ TypeInfo { name: "id", is_optional: false, - is_list: false, description: Some( "ID of the search job", ), - type_description: None, }, ), ], @@ -3548,11 +3208,9 @@ TypeInfo { name: "id", is_optional: true, - is_list: false, description: Some( "ID of the search job. If not specified, all search jobs are returned", ), - type_description: None, }, ), ], @@ -3565,33 +3223,27 @@ TypeInfo { name: "id", is_optional: false, - is_list: false, description: Some( "ID of the search job", ), - type_description: None, }, ), String( TypeInfo { name: "status", is_optional: false, - is_list: false, description: Some( "Current status of the search job (either Running or Stopped)", ), - type_description: None, }, ), Number( TypeInfo { name: "total", is_optional: false, - is_list: false, description: Some( "Total number of results. If the status is Running this number may contineu to increase", ), - type_description: None, }, ), ], @@ -3615,33 +3267,27 @@ TypeInfo { name: "id", is_optional: false, - is_list: false, description: Some( "ID of the search job", ), - type_description: None, }, ), Number( TypeInfo { name: "limit", is_optional: true, - is_list: false, description: Some( "max number of results to return. 0 or negative means no limit", ), - type_description: None, }, ), Number( TypeInfo { name: "offset", is_optional: true, - is_list: false, description: Some( "result to start at. A negative number means count backwards (e.g. -2 returns the 2 most recent results)", ), - type_description: None, }, ), ], @@ -3655,77 +3301,63 @@ TypeInfo { name: "descrLink", is_optional: false, - is_list: false, description: Some( "URL of the torrent's description page", ), - type_description: None, }, ), String( TypeInfo { name: "fileName", is_optional: false, - is_list: false, description: Some( "Name of the file", ), - type_description: None, }, ), Number( TypeInfo { name: "fileSize", is_optional: false, - is_list: false, description: Some( "Size of the file in Bytes", ), - type_description: None, }, ), String( TypeInfo { name: "fileUrl", is_optional: false, - is_list: false, description: Some( "Torrent download link (usually either .torrent file or magnet link)", ), - type_description: None, }, ), Number( TypeInfo { name: "nbLeechers", is_optional: false, - is_list: false, description: Some( "Number of leechers", ), - type_description: None, }, ), Number( TypeInfo { name: "nbSeeders", is_optional: false, - is_list: false, description: Some( "Number of seeders", ), - type_description: None, }, ), String( TypeInfo { name: "siteUrl", is_optional: false, - is_list: false, description: Some( "URL of the torrent site", ), - type_description: None, }, ), ], @@ -3739,11 +3371,9 @@ type_info: TypeInfo { name: "results", is_optional: false, - is_list: false, description: Some( "Array of result objects- see table below", ), - type_description: None, }, ref_type: "Result", }, @@ -3752,22 +3382,18 @@ TypeInfo { name: "status", is_optional: false, - is_list: false, description: Some( "Current status of the search job (either Running or Stopped)", ), - type_description: None, }, ), Number( TypeInfo { name: "total", is_optional: false, - is_list: false, description: Some( "Total number of results. If the status is Running this number may continue to increase", ), - type_description: None, }, ), ], @@ -3789,11 +3415,9 @@ TypeInfo { name: "id", is_optional: false, - is_list: false, description: Some( "ID of the search job", ), - type_description: None, }, ), ], @@ -3817,66 +3441,54 @@ TypeInfo { name: "enabled", is_optional: false, - is_list: false, description: Some( "Whether the plugin is enabled", ), - type_description: None, }, ), String( TypeInfo { name: "fullName", is_optional: false, - is_list: false, description: Some( "Full name of the plugin", ), - type_description: None, }, ), String( TypeInfo { name: "name", is_optional: false, - is_list: false, description: Some( "Short name of the plugin", ), - type_description: None, }, ), StringArray( TypeInfo { name: "supportedCategories", is_optional: false, - is_list: false, description: Some( "List of category objects", ), - type_description: None, }, ), String( TypeInfo { name: "url", is_optional: false, - is_list: false, description: Some( "URL of the torrent site", ), - type_description: None, }, ), String( TypeInfo { name: "version", is_optional: false, - is_list: false, description: Some( "Installed version of the plugin", ), - type_description: None, }, ), ], @@ -3898,11 +3510,9 @@ TypeInfo { name: "sources", is_optional: false, - is_list: false, description: Some( "Url or file path of the plugin to install (e.g. \"[https://raw.githubusercontent.com/qbittorrent/search-plugins/master/nova3/engines/legittorrents.py](https://raw.githubusercontent.com/qbittorrent/search-plugins/master/nova3/engines/legittorrents.py)\"). Supports multiple sources separated by \\", ), - type_description: None, }, ), ], @@ -3924,11 +3534,9 @@ TypeInfo { name: "names", is_optional: false, - is_list: false, description: Some( "Name of the plugin to uninstall (e.g. \"legittorrents\"). Supports multiple names separated by \\", ), - type_description: None, }, ), ], @@ -3950,22 +3558,18 @@ TypeInfo { name: "names", is_optional: false, - is_list: false, description: Some( "Name of the plugin to enable/disable (e.g. \"legittorrents\"). Supports multiple names separated by \\", ), - type_description: None, }, ), Bool( TypeInfo { name: "enable", is_optional: false, - is_list: false, description: Some( "Whether the plugins should be enabled", ), - type_description: None, }, ), ], diff --git a/qbittorrent-web-api-gen/src/generate/group/mod.rs b/qbittorrent-web-api-gen/src/generate/group/mod.rs index d4bb2f0..5a392eb 100644 --- a/qbittorrent-web-api-gen/src/generate/group/mod.rs +++ b/qbittorrent-web-api-gen/src/generate/group/mod.rs @@ -127,10 +127,6 @@ impl parser::ApiMethod { } } - fn name_camel(&self) -> Ident { - util::to_ident(&self.name.to_camel()) - } - fn name_snake(&self) -> Ident { util::to_ident(&self.name.to_snake()) } @@ -169,10 +165,6 @@ impl types::Type { self.get_type_info().name.clone() } - fn name_camel(&self) -> Ident { - util::to_ident(&self.name().to_camel()) - } - fn name_snake(&self) -> Ident { util::to_ident(&self.name().to_snake()) } @@ -218,10 +210,6 @@ impl parser::EnumValue { fn name_camel(&self) -> Ident { util::to_ident(&self.value.to_camel()) } - - fn name_snake(&self) -> Ident { - util::to_ident(&self.value.to_snake()) - } } #[derive(Debug)] diff --git a/qbittorrent-web-api-gen/src/parser/group/method/method_tests/search_result.check b/qbittorrent-web-api-gen/src/parser/group/method/method_tests/search_result.check index 72dd726..1f2c06b 100644 --- a/qbittorrent-web-api-gen/src/parser/group/method/method_tests/search_result.check +++ b/qbittorrent-web-api-gen/src/parser/group/method/method_tests/search_result.check @@ -13,33 +13,27 @@ ApiMethod { TypeInfo { name: "id", is_optional: false, - is_list: false, description: Some( "ID of the search job", ), - type_description: None, }, ), Number( TypeInfo { name: "limit", is_optional: true, - is_list: false, description: Some( "max number of results to return. 0 or negative means no limit", ), - type_description: None, }, ), Number( TypeInfo { name: "offset", is_optional: true, - is_list: false, description: Some( "result to start at. A negative number means count backwards (e.g. -2 returns the 2 most recent results)", ), - type_description: None, }, ), ], @@ -53,77 +47,63 @@ ApiMethod { TypeInfo { name: "descrLink", is_optional: false, - is_list: false, description: Some( "URL of the torrent's description page", ), - type_description: None, }, ), String( TypeInfo { name: "fileName", is_optional: false, - is_list: false, description: Some( "Name of the file", ), - type_description: None, }, ), Number( TypeInfo { name: "fileSize", is_optional: false, - is_list: false, description: Some( "Size of the file in Bytes", ), - type_description: None, }, ), String( TypeInfo { name: "fileUrl", is_optional: false, - is_list: false, description: Some( "Torrent download link (usually either .torrent file or magnet link)", ), - type_description: None, }, ), Number( TypeInfo { name: "nbLeechers", is_optional: false, - is_list: false, description: Some( "Number of leechers", ), - type_description: None, }, ), Number( TypeInfo { name: "nbSeeders", is_optional: false, - is_list: false, description: Some( "Number of seeders", ), - type_description: None, }, ), String( TypeInfo { name: "siteUrl", is_optional: false, - is_list: false, description: Some( "URL of the torrent site", ), - type_description: None, }, ), ], @@ -137,11 +117,9 @@ ApiMethod { type_info: TypeInfo { name: "results", is_optional: false, - is_list: false, description: Some( "Array of result objects- see table below", ), - type_description: None, }, ref_type: "Result", }, @@ -150,22 +128,18 @@ ApiMethod { TypeInfo { name: "status", is_optional: false, - is_list: false, description: Some( "Current status of the search job (either Running or Stopped)", ), - type_description: None, }, ), Number( TypeInfo { name: "total", is_optional: false, - is_list: false, description: Some( "Total number of results. If the status is Running this number may continue to increase", ), - type_description: None, }, ), ], diff --git a/qbittorrent-web-api-gen/src/parser/group/method/mod.rs b/qbittorrent-web-api-gen/src/parser/group/method/mod.rs index 5f03a1a..49d96ec 100644 --- a/qbittorrent-web-api-gen/src/parser/group/method/mod.rs +++ b/qbittorrent-web-api-gen/src/parser/group/method/mod.rs @@ -5,7 +5,7 @@ mod url; use crate::{md_parser, types}; use case::CaseExt; use regex::Regex; -use std::collections::{BTreeMap, HashMap}; +use std::collections::BTreeMap; #[derive(Debug)] pub struct ApiMethod { @@ -312,13 +312,6 @@ impl md_parser::Table { impl md_parser::TableRow { fn to_type(&self) -> Option { - self.to_types_with_types(&HashMap::new()) - } - - fn to_types_with_types( - &self, - type_map: &HashMap, - ) -> Option { let columns = &self.columns; let description = columns.get(2).cloned(); @@ -327,9 +320,9 @@ impl md_parser::TableRow { Some(desc) if desc.contains("default: ") => { // type defines a variable as default if it contains: _optional_ let name_with_optional = format!("{} {}", columns[0], types::OPTIONAL); - types::Type::from(&columns[1], &name_with_optional, description, type_map) + types::Type::from(&columns[1], &name_with_optional, description) } - _ => types::Type::from(&columns[1], &columns[0], description, type_map), + _ => types::Type::from(&columns[1], &columns[0], description), } } } diff --git a/qbittorrent-web-api-gen/src/types.rs b/qbittorrent-web-api-gen/src/types.rs index b216cc2..b56561f 100644 --- a/qbittorrent-web-api-gen/src/types.rs +++ b/qbittorrent-web-api-gen/src/types.rs @@ -1,5 +1,3 @@ -use std::collections::HashMap; - use case::CaseExt; use regex::RegexBuilder; @@ -18,25 +16,17 @@ pub struct TypeDescription { pub struct TypeInfo { pub name: String, pub is_optional: bool, - is_list: bool, + // is_list: bool, pub description: Option, - pub type_description: Option, } impl TypeInfo { - pub fn new( - name: &str, - is_optional: bool, - is_list: bool, - description: Option, - type_description: Option, - ) -> Self { + pub fn new(name: &str, is_optional: bool, description: Option) -> Self { Self { name: name.into(), is_optional, - is_list, + // is_list, description, - type_description, } } } @@ -84,9 +74,9 @@ impl Type { } } - pub fn is_list(&self) -> bool { - self.get_type_info().is_list || matches!(self, Type::StringArray(_)) - } + // pub fn is_list(&self) -> bool { + // self.get_type_info().is_list || matches!(self, Type::StringArray(_)) + // } pub fn to_borrowed_type(&self) -> String { match self { @@ -118,13 +108,7 @@ impl Type { } } - pub fn from( - type_as_str: &str, - name: &str, - description: Option, - types: &HashMap, - ) -> Option { - let available_types = types.get(name).cloned(); + pub fn from(type_as_str: &str, name: &str, description: Option) -> Option { let type_name = match name.split_once(OPTIONAL) { Some((split, _)) => split, None => name, @@ -132,15 +116,7 @@ impl Type { .trim(); let is_optional = name.contains(OPTIONAL); - let create_type_info = || { - TypeInfo::new( - type_name, - is_optional, - false, - description.clone(), - available_types.clone(), - ) - }; + let create_type_info = || TypeInfo::new(type_name, is_optional, description.clone()); let create_object_type = |name: &str| { Some(Type::Object(Object { From 4a1db65877385ff737aa2f1ccfb87cfdd4b7b2ab Mon Sep 17 00:00:00 2001 From: Joel Wachsler Date: Fri, 22 Jul 2022 21:55:26 +0000 Subject: [PATCH 41/47] Progress --- qbittorrent-web-api-gen/groups.txt | 209 +++++++++++++++++- .../src/generate/group/mod.rs | 192 +++++++++------- .../method/method_tests/search_result.check | 13 ++ .../src/parser/group/method/mod.rs | 32 +-- qbittorrent-web-api-gen/src/types.rs | 18 +- 5 files changed, 344 insertions(+), 120 deletions(-) diff --git a/qbittorrent-web-api-gen/groups.txt b/qbittorrent-web-api-gen/groups.txt index 7e19da5..8edc7b7 100644 --- a/qbittorrent-web-api-gen/groups.txt +++ b/qbittorrent-web-api-gen/groups.txt @@ -17,6 +17,7 @@ TypeInfo { name: "username", is_optional: false, + is_list: false, description: Some( "Username used to access the WebUI", ), @@ -26,6 +27,7 @@ TypeInfo { name: "password", is_optional: false, + is_list: false, description: Some( "Password used to access the WebUI", ), @@ -89,6 +91,7 @@ TypeInfo { name: "qt", is_optional: false, + is_list: false, description: Some( "QT version", ), @@ -98,6 +101,7 @@ TypeInfo { name: "libtorrent", is_optional: false, + is_list: false, description: Some( "libtorrent version", ), @@ -107,6 +111,7 @@ TypeInfo { name: "boost", is_optional: false, + is_list: false, description: Some( "Boost version", ), @@ -116,6 +121,7 @@ TypeInfo { name: "openssl", is_optional: false, + is_list: false, description: Some( "OpenSSL version", ), @@ -125,6 +131,7 @@ TypeInfo { name: "bitness", is_optional: false, + is_list: false, description: Some( "Application bitness (e.g. 64-bit)", ), @@ -521,6 +528,7 @@ TypeInfo { name: "normal", is_optional: true, + is_list: false, description: Some( "Include normal messages (default: true)", ), @@ -530,6 +538,7 @@ TypeInfo { name: "info", is_optional: true, + is_list: false, description: Some( "Include info messages (default: true)", ), @@ -539,6 +548,7 @@ TypeInfo { name: "warning", is_optional: true, + is_list: false, description: Some( "Include warning messages (default: true)", ), @@ -548,6 +558,7 @@ TypeInfo { name: "critical", is_optional: true, + is_list: false, description: Some( "Include critical messages (default: true)", ), @@ -557,6 +568,7 @@ TypeInfo { name: "last_known_id", is_optional: true, + is_list: false, description: Some( "Exclude messages with \"message id\" <= last_known_id (default: -1)", ), @@ -583,6 +595,7 @@ TypeInfo { name: "last_known_id", is_optional: true, + is_list: false, description: Some( "Exclude messages with \"message id\" <= last_known_id (default: -1)", ), @@ -618,6 +631,7 @@ TypeInfo { name: "rid", is_optional: false, + is_list: false, description: Some( "Response ID. If not provided, rid=0 will be assumed. If the given rid is different from the one of last server reply, full_update will be true (see the server reply details for more info)", ), @@ -633,6 +647,7 @@ TypeInfo { name: "rid", is_optional: false, + is_list: false, description: Some( "Response ID", ), @@ -642,6 +657,7 @@ TypeInfo { name: "full_update", is_optional: false, + is_list: false, description: Some( "Whether the response contains all the data or partial data", ), @@ -652,6 +668,7 @@ type_info: TypeInfo { name: "torrents", is_optional: false, + is_list: false, description: Some( "Property: torrent hash, value: same as [torrent list](#get-torrent-list)", ), @@ -663,6 +680,7 @@ TypeInfo { name: "torrents_removed", is_optional: false, + is_list: false, description: Some( "List of hashes of torrents removed since last request", ), @@ -673,6 +691,7 @@ type_info: TypeInfo { name: "categories", is_optional: false, + is_list: false, description: Some( "Info for categories added since last request", ), @@ -684,6 +703,7 @@ TypeInfo { name: "categories_removed", is_optional: false, + is_list: false, description: Some( "List of categories removed since last request", ), @@ -693,6 +713,7 @@ TypeInfo { name: "tags", is_optional: false, + is_list: false, description: Some( "List of tags added since last request", ), @@ -702,6 +723,7 @@ TypeInfo { name: "tags_removed", is_optional: false, + is_list: false, description: Some( "List of tags removed since last request", ), @@ -712,6 +734,7 @@ type_info: TypeInfo { name: "server_state", is_optional: false, + is_list: false, description: Some( "Global transfer info", ), @@ -740,6 +763,7 @@ TypeInfo { name: "hash", is_optional: false, + is_list: false, description: Some( "Torrent hash", ), @@ -749,6 +773,7 @@ TypeInfo { name: "rid", is_optional: false, + is_list: false, description: Some( "Response ID. If not provided, rid=0 will be assumed. If the given rid is different from the one of last server reply, full_update will be true (see the server reply details for more info)", ), @@ -784,6 +809,7 @@ TypeInfo { name: "dl_info_speed", is_optional: false, + is_list: false, description: Some( "Global download rate (bytes/s)", ), @@ -793,6 +819,7 @@ TypeInfo { name: "dl_info_data", is_optional: false, + is_list: false, description: Some( "Data downloaded this session (bytes)", ), @@ -802,6 +829,7 @@ TypeInfo { name: "up_info_speed", is_optional: false, + is_list: false, description: Some( "Global upload rate (bytes/s)", ), @@ -811,6 +839,7 @@ TypeInfo { name: "up_info_data", is_optional: false, + is_list: false, description: Some( "Data uploaded this session (bytes)", ), @@ -820,6 +849,7 @@ TypeInfo { name: "dl_rate_limit", is_optional: false, + is_list: false, description: Some( "Download rate limit (bytes/s)", ), @@ -829,6 +859,7 @@ TypeInfo { name: "up_rate_limit", is_optional: false, + is_list: false, description: Some( "Upload rate limit (bytes/s)", ), @@ -838,6 +869,7 @@ TypeInfo { name: "dht_nodes", is_optional: false, + is_list: false, description: Some( "DHT nodes connected to", ), @@ -847,6 +879,7 @@ TypeInfo { name: "connection_status", is_optional: false, + is_list: false, description: Some( "Connection status. See possible values here below", ), @@ -899,6 +932,7 @@ TypeInfo { name: "limit", is_optional: false, + is_list: false, description: Some( "The global download speed limit to set in bytes/second", ), @@ -933,6 +967,7 @@ TypeInfo { name: "limit", is_optional: false, + is_list: false, description: Some( "The global upload speed limit to set in bytes/second", ), @@ -957,6 +992,7 @@ TypeInfo { name: "peers", is_optional: false, + is_list: false, description: Some( "The peer to ban, or multiple peers separated by a pipe \\", ), @@ -992,6 +1028,7 @@ TypeInfo { name: "filter", is_optional: true, + is_list: false, description: Some( "Filter torrent list by state. Allowed state filters: all, downloading, seeding, completed, paused, active, inactive, resumed, stalled, stalled_uploading, stalled_downloading, errored", ), @@ -1001,6 +1038,7 @@ TypeInfo { name: "category", is_optional: true, + is_list: false, description: Some( "Get torrents with the given category (empty string means \"without category\"; no \"category\" parameter means \"any category\" <- broken until [#11748](https://github.com/qbittorrent/qBittorrent/issues/11748) is resolved). Remember to URL-encode the category name. For example, My category becomes My%20category", ), @@ -1010,6 +1048,7 @@ TypeInfo { name: "tag", is_optional: true, + is_list: false, description: Some( "Get torrents with the given tag (empty string means \"without tag\"; no \"tag\" parameter means \"any tag\". Remember to URL-encode the category name. For example, My tag becomes My%20tag", ), @@ -1019,6 +1058,7 @@ TypeInfo { name: "sort", is_optional: true, + is_list: true, description: Some( "Sort torrents by given key. They can be sorted using any field of the response's JSON array (which are documented below) as the sort key.", ), @@ -1028,6 +1068,7 @@ TypeInfo { name: "reverse", is_optional: true, + is_list: false, description: Some( "Enable reverse sorting. Defaults to false", ), @@ -1037,6 +1078,7 @@ TypeInfo { name: "limit", is_optional: true, + is_list: false, description: Some( "Limit the number of torrents returned", ), @@ -1046,6 +1088,7 @@ TypeInfo { name: "offset", is_optional: true, + is_list: false, description: Some( "Set offset (if less than 0, offset from end)", ), @@ -1055,6 +1098,7 @@ TypeInfo { name: "hashes", is_optional: true, + is_list: false, description: Some( "Filter by hashes. Can contain multiple hashes separated by \\", ), @@ -1210,6 +1254,7 @@ TypeInfo { name: "added_on", is_optional: false, + is_list: false, description: Some( "Time (Unix Epoch) when the torrent was added to the client", ), @@ -1219,6 +1264,7 @@ TypeInfo { name: "amount_left", is_optional: false, + is_list: false, description: Some( "Amount of data left to download (bytes)", ), @@ -1228,6 +1274,7 @@ TypeInfo { name: "auto_tmm", is_optional: false, + is_list: false, description: Some( "Whether this torrent is managed by Automatic Torrent Management", ), @@ -1237,6 +1284,7 @@ TypeInfo { name: "availability", is_optional: false, + is_list: false, description: Some( "Percentage of file pieces currently available", ), @@ -1246,6 +1294,7 @@ TypeInfo { name: "category", is_optional: false, + is_list: false, description: Some( "Category of the torrent", ), @@ -1255,6 +1304,7 @@ TypeInfo { name: "completed", is_optional: false, + is_list: false, description: Some( "Amount of transfer data completed (bytes)", ), @@ -1264,6 +1314,7 @@ TypeInfo { name: "completion_on", is_optional: false, + is_list: false, description: Some( "Time (Unix Epoch) when the torrent completed", ), @@ -1273,6 +1324,7 @@ TypeInfo { name: "content_path", is_optional: false, + is_list: false, description: Some( "Absolute path of torrent content (root path for multifile torrents, absolute file path for singlefile torrents)", ), @@ -1282,6 +1334,7 @@ TypeInfo { name: "dl_limit", is_optional: false, + is_list: false, description: Some( "Torrent download speed limit (bytes/s). -1 if ulimited.", ), @@ -1291,6 +1344,7 @@ TypeInfo { name: "dlspeed", is_optional: false, + is_list: false, description: Some( "Torrent download speed (bytes/s)", ), @@ -1300,6 +1354,7 @@ TypeInfo { name: "downloaded", is_optional: false, + is_list: false, description: Some( "Amount of data downloaded", ), @@ -1309,6 +1364,7 @@ TypeInfo { name: "downloaded_session", is_optional: false, + is_list: false, description: Some( "Amount of data downloaded this session", ), @@ -1318,6 +1374,7 @@ TypeInfo { name: "eta", is_optional: false, + is_list: false, description: Some( "Torrent ETA (seconds)", ), @@ -1327,6 +1384,7 @@ TypeInfo { name: "f_l_piece_prio", is_optional: false, + is_list: false, description: Some( "True if first last piece are prioritized", ), @@ -1336,6 +1394,7 @@ TypeInfo { name: "force_start", is_optional: false, + is_list: false, description: Some( "True if force start is enabled for this torrent", ), @@ -1345,6 +1404,7 @@ TypeInfo { name: "hash", is_optional: false, + is_list: false, description: Some( "Torrent hash", ), @@ -1354,6 +1414,7 @@ TypeInfo { name: "last_activity", is_optional: false, + is_list: false, description: Some( "Last time (Unix Epoch) when a chunk was downloaded/uploaded", ), @@ -1363,6 +1424,7 @@ TypeInfo { name: "magnet_uri", is_optional: false, + is_list: false, description: Some( "Magnet URI corresponding to this torrent", ), @@ -1372,6 +1434,7 @@ TypeInfo { name: "max_ratio", is_optional: false, + is_list: false, description: Some( "Maximum share ratio until torrent is stopped from seeding/uploading", ), @@ -1381,6 +1444,7 @@ TypeInfo { name: "max_seeding_time", is_optional: false, + is_list: false, description: Some( "Maximum seeding time (seconds) until torrent is stopped from seeding", ), @@ -1390,6 +1454,7 @@ TypeInfo { name: "name", is_optional: false, + is_list: false, description: Some( "Torrent name", ), @@ -1399,6 +1464,7 @@ TypeInfo { name: "num_complete", is_optional: false, + is_list: false, description: Some( "Number of seeds in the swarm", ), @@ -1408,6 +1474,7 @@ TypeInfo { name: "num_incomplete", is_optional: false, + is_list: false, description: Some( "Number of leechers in the swarm", ), @@ -1417,6 +1484,7 @@ TypeInfo { name: "num_leechs", is_optional: false, + is_list: false, description: Some( "Number of leechers connected to", ), @@ -1426,6 +1494,7 @@ TypeInfo { name: "num_seeds", is_optional: false, + is_list: false, description: Some( "Number of seeds connected to", ), @@ -1435,6 +1504,7 @@ TypeInfo { name: "priority", is_optional: false, + is_list: false, description: Some( "Torrent priority. Returns -1 if queuing is disabled or torrent is in seed mode", ), @@ -1444,6 +1514,7 @@ TypeInfo { name: "progress", is_optional: false, + is_list: false, description: Some( "Torrent progress (percentage/100)", ), @@ -1453,6 +1524,7 @@ TypeInfo { name: "ratio", is_optional: false, + is_list: false, description: Some( "Torrent share ratio. Max ratio value: 9999.", ), @@ -1462,6 +1534,7 @@ TypeInfo { name: "ratio_limit", is_optional: false, + is_list: false, description: Some( "TODO (what is different from max_ratio?)", ), @@ -1471,6 +1544,7 @@ TypeInfo { name: "save_path", is_optional: false, + is_list: false, description: Some( "Path where this torrent's data is stored", ), @@ -1480,6 +1554,7 @@ TypeInfo { name: "seeding_time", is_optional: false, + is_list: false, description: Some( "Torrent elapsed time while complete (seconds)", ), @@ -1489,6 +1564,7 @@ TypeInfo { name: "seeding_time_limit", is_optional: false, + is_list: false, description: Some( "TODO (what is different from max_seeding_time?) seeding_time_limit is a per torrent setting, when Automatic Torrent Management is disabled, furthermore then max_seeding_time is set to seeding_time_limit for this torrent. If Automatic Torrent Management is enabled, the value is -2. And if max_seeding_time is unset it have a default value -1.", ), @@ -1498,6 +1574,7 @@ TypeInfo { name: "seen_complete", is_optional: false, + is_list: false, description: Some( "Time (Unix Epoch) when this torrent was last seen complete", ), @@ -1507,6 +1584,7 @@ TypeInfo { name: "seq_dl", is_optional: false, + is_list: false, description: Some( "True if sequential download is enabled", ), @@ -1516,6 +1594,7 @@ TypeInfo { name: "size", is_optional: false, + is_list: false, description: Some( "Total size (bytes) of files selected for download", ), @@ -1525,6 +1604,7 @@ TypeInfo { name: "state", is_optional: false, + is_list: false, description: Some( "Torrent state. See table here below for the possible values", ), @@ -1534,6 +1614,7 @@ TypeInfo { name: "super_seeding", is_optional: false, + is_list: false, description: Some( "True if super seeding is enabled", ), @@ -1543,6 +1624,7 @@ TypeInfo { name: "tags", is_optional: false, + is_list: false, description: Some( "Comma-concatenated tag list of the torrent", ), @@ -1552,6 +1634,7 @@ TypeInfo { name: "time_active", is_optional: false, + is_list: false, description: Some( "Total active time (seconds)", ), @@ -1561,6 +1644,7 @@ TypeInfo { name: "total_size", is_optional: false, + is_list: false, description: Some( "Total size (bytes) of all file in this torrent (including unselected ones)", ), @@ -1570,6 +1654,7 @@ TypeInfo { name: "tracker", is_optional: false, + is_list: false, description: Some( "The first tracker with working status. Returns empty string if no tracker is working.", ), @@ -1579,6 +1664,7 @@ TypeInfo { name: "up_limit", is_optional: false, + is_list: false, description: Some( "Torrent upload speed limit (bytes/s). -1 if ulimited.", ), @@ -1588,6 +1674,7 @@ TypeInfo { name: "uploaded", is_optional: false, + is_list: false, description: Some( "Amount of data uploaded", ), @@ -1597,6 +1684,7 @@ TypeInfo { name: "uploaded_session", is_optional: false, + is_list: false, description: Some( "Amount of data uploaded this session", ), @@ -1606,6 +1694,7 @@ TypeInfo { name: "upspeed", is_optional: false, + is_list: false, description: Some( "Torrent upload speed (bytes/s)", ), @@ -1632,6 +1721,7 @@ TypeInfo { name: "hash", is_optional: false, + is_list: false, description: Some( "The hash of the torrent you want to get the generic properties of", ), @@ -1658,6 +1748,7 @@ TypeInfo { name: "hash", is_optional: false, + is_list: false, description: Some( "The hash of the torrent you want to get the trackers of", ), @@ -1715,6 +1806,7 @@ TypeInfo { name: "url", is_optional: false, + is_list: false, description: Some( "Tracker url", ), @@ -1724,6 +1816,7 @@ TypeInfo { name: "status", is_optional: false, + is_list: false, description: Some( "Tracker status. See the table below for possible values", ), @@ -1733,6 +1826,7 @@ TypeInfo { name: "tier", is_optional: false, + is_list: false, description: Some( "Tracker priority tier. Lower tier trackers are tried before higher tiers. Tier numbers are valid when >= 0, < 0 is used as placeholder when tier does not exist for special entries (such as DHT).", ), @@ -1742,6 +1836,7 @@ TypeInfo { name: "num_peers", is_optional: false, + is_list: false, description: Some( "Number of peers for current torrent, as reported by the tracker", ), @@ -1751,6 +1846,7 @@ TypeInfo { name: "num_seeds", is_optional: false, + is_list: false, description: Some( "Number of seeds for current torrent, asreported by the tracker", ), @@ -1760,6 +1856,7 @@ TypeInfo { name: "num_leeches", is_optional: false, + is_list: false, description: Some( "Number of leeches for current torrent, as reported by the tracker", ), @@ -1769,6 +1866,7 @@ TypeInfo { name: "num_downloaded", is_optional: false, + is_list: false, description: Some( "Number of completed downlods for current torrent, as reported by the tracker", ), @@ -1778,6 +1876,7 @@ TypeInfo { name: "msg", is_optional: false, + is_list: false, description: Some( "Tracker message (there is no way of knowing what this message is - it's up to tracker admins)", ), @@ -1804,6 +1903,7 @@ TypeInfo { name: "hash", is_optional: false, + is_list: false, description: Some( "The hash of the torrent you want to get the webseeds of", ), @@ -1819,6 +1919,7 @@ TypeInfo { name: "url", is_optional: false, + is_list: false, description: Some( "URL of the web seed", ), @@ -1845,6 +1946,7 @@ TypeInfo { name: "hash", is_optional: false, + is_list: false, description: Some( "The hash of the torrent you want to get the contents of", ), @@ -1854,6 +1956,7 @@ TypeInfo { name: "indexes", is_optional: true, + is_list: false, description: Some( "The indexes of the files you want to retrieve. indexes can contain multiple values separated by \\", ), @@ -1915,6 +2018,7 @@ TypeInfo { name: "hash", is_optional: false, + is_list: false, description: Some( "The hash of the torrent you want to get the pieces' states of", ), @@ -1941,6 +2045,7 @@ TypeInfo { name: "hash", is_optional: false, + is_list: false, description: Some( "The hash of the torrent you want to get the pieces' hashes of", ), @@ -1965,6 +2070,7 @@ TypeInfo { name: "hashes", is_optional: false, + is_list: false, description: Some( "The hashes of the torrents you want to pause. hashes can contain multiple hashes separated by \\", ), @@ -1989,6 +2095,7 @@ TypeInfo { name: "hashes", is_optional: false, + is_list: false, description: Some( "The hashes of the torrents you want to resume. hashes can contain multiple hashes separated by \\", ), @@ -2013,6 +2120,7 @@ TypeInfo { name: "hashes", is_optional: false, + is_list: false, description: Some( "The hashes of the torrents you want to delete. hashes can contain multiple hashes separated by \\", ), @@ -2023,6 +2131,7 @@ type_info: TypeInfo { name: "deleteFiles", is_optional: false, + is_list: false, description: None, }, ref_type: "If set to true, the downloaded data will also be deleted, otherwise has no effect.", @@ -2047,6 +2156,7 @@ TypeInfo { name: "hashes", is_optional: false, + is_list: false, description: Some( "The hashes of the torrents you want to recheck. hashes can contain multiple hashes separated by \\", ), @@ -2071,6 +2181,7 @@ TypeInfo { name: "hashes", is_optional: false, + is_list: false, description: Some( "The hashes of the torrents you want to reannounce. hashes can contain multiple hashes separated by \\", ), @@ -2095,27 +2206,17 @@ TypeInfo { name: "urls", is_optional: false, + is_list: false, description: Some( "URLs separated with newlines", ), }, ), - Object( - Object { - type_info: TypeInfo { - name: "torrents", - is_optional: false, - description: Some( - "Raw data of torrent file. torrents can be presented multiple times.", - ), - }, - ref_type: "Raw", - }, - ), String( TypeInfo { name: "savepath", is_optional: true, + is_list: false, description: Some( "Download folder", ), @@ -2125,6 +2226,7 @@ TypeInfo { name: "cookie", is_optional: true, + is_list: false, description: Some( "Cookie sent to download the .torrent file", ), @@ -2134,6 +2236,7 @@ TypeInfo { name: "category", is_optional: true, + is_list: false, description: Some( "Category for the torrent", ), @@ -2143,6 +2246,7 @@ TypeInfo { name: "tags", is_optional: true, + is_list: false, description: Some( "Tags for the torrent, split by ','", ), @@ -2152,6 +2256,7 @@ TypeInfo { name: "skip_checking", is_optional: true, + is_list: false, description: Some( "Skip hash checking. Possible values are true, false (default)", ), @@ -2161,6 +2266,7 @@ TypeInfo { name: "paused", is_optional: true, + is_list: false, description: Some( "Add torrents in the paused state. Possible values are true, false (default)", ), @@ -2170,6 +2276,7 @@ TypeInfo { name: "root_folder", is_optional: true, + is_list: false, description: Some( "Create the root folder. Possible values are true, false, unset (default)", ), @@ -2179,6 +2286,7 @@ TypeInfo { name: "rename", is_optional: true, + is_list: false, description: Some( "Rename torrent", ), @@ -2188,6 +2296,7 @@ TypeInfo { name: "upLimit", is_optional: true, + is_list: false, description: Some( "Set torrent upload speed limit. Unit in bytes/second", ), @@ -2197,6 +2306,7 @@ TypeInfo { name: "dlLimit", is_optional: true, + is_list: false, description: Some( "Set torrent download speed limit. Unit in bytes/second", ), @@ -2206,6 +2316,7 @@ TypeInfo { name: "ratioLimit", is_optional: true, + is_list: false, description: Some( "Set torrent share ratio limit", ), @@ -2215,6 +2326,7 @@ TypeInfo { name: "seedingTimeLimit", is_optional: true, + is_list: false, description: Some( "Set torrent seeding time limit. Unit in seconds", ), @@ -2224,6 +2336,7 @@ TypeInfo { name: "autoTMM", is_optional: true, + is_list: false, description: Some( "Whether Automatic Torrent Management should be used", ), @@ -2233,6 +2346,7 @@ TypeInfo { name: "sequentialDownload", is_optional: true, + is_list: false, description: Some( "Enable sequential download. Possible values are true, false (default)", ), @@ -2242,6 +2356,7 @@ TypeInfo { name: "firstLastPiecePrio", is_optional: true, + is_list: false, description: Some( "Prioritize download first last piece. Possible values are true, false (default)", ), @@ -2274,6 +2389,7 @@ TypeInfo { name: "hash", is_optional: false, + is_list: false, description: Some( "The hash of the torrent", ), @@ -2283,6 +2399,7 @@ TypeInfo { name: "origUrl", is_optional: false, + is_list: false, description: Some( "The tracker URL you want to edit", ), @@ -2292,6 +2409,7 @@ TypeInfo { name: "newUrl", is_optional: false, + is_list: false, description: Some( "The new URL to replace the origUrl", ), @@ -2316,6 +2434,7 @@ TypeInfo { name: "hash", is_optional: false, + is_list: false, description: Some( "The hash of the torrent", ), @@ -2325,6 +2444,7 @@ TypeInfo { name: "urls", is_optional: false, + is_list: false, description: Some( "URLs to remove, separated by \\", ), @@ -2349,6 +2469,7 @@ TypeInfo { name: "hashes", is_optional: false, + is_list: false, description: Some( "The hash of the torrent, or multiple hashes separated by a pipe \\", ), @@ -2358,6 +2479,7 @@ TypeInfo { name: "peers", is_optional: false, + is_list: false, description: Some( "The peer to add, or multiple peers separated by a pipe \\", ), @@ -2382,6 +2504,7 @@ TypeInfo { name: "hashes", is_optional: false, + is_list: false, description: Some( "The hashes of the torrents you want to increase the priority of. hashes can contain multiple hashes separated by \\", ), @@ -2406,6 +2529,7 @@ TypeInfo { name: "hashes", is_optional: false, + is_list: false, description: Some( "The hashes of the torrents you want to decrease the priority of. hashes can contain multiple hashes separated by \\", ), @@ -2430,6 +2554,7 @@ TypeInfo { name: "hashes", is_optional: false, + is_list: false, description: Some( "The hashes of the torrents you want to set to the maximum priority. hashes can contain multiple hashes separated by \\", ), @@ -2454,6 +2579,7 @@ TypeInfo { name: "hashes", is_optional: false, + is_list: false, description: Some( "The hashes of the torrents you want to set to the minimum priority. hashes can contain multiple hashes separated by \\", ), @@ -2478,6 +2604,7 @@ TypeInfo { name: "hash", is_optional: false, + is_list: false, description: Some( "The hash of the torrent", ), @@ -2487,6 +2614,7 @@ TypeInfo { name: "id", is_optional: false, + is_list: false, description: Some( "File ids, separated by \\", ), @@ -2496,6 +2624,7 @@ TypeInfo { name: "priority", is_optional: false, + is_list: false, description: Some( "File priority to set (consult [torrent contents API](#get-torrent-contents) for possible values)", ), @@ -2656,6 +2785,7 @@ TypeInfo { name: "hashes", is_optional: false, + is_list: false, description: Some( "The hashes of the torrents you want to toggle sequential download for. hashes can contain multiple hashes separated by \\", ), @@ -2680,6 +2810,7 @@ TypeInfo { name: "hashes", is_optional: false, + is_list: false, description: Some( "The hashes of the torrents you want to toggle the first/last piece priority for. hashes can contain multiple hashes separated by \\", ), @@ -2720,6 +2851,7 @@ TypeInfo { name: "hash", is_optional: false, + is_list: false, description: Some( "The hash of the torrent", ), @@ -2729,6 +2861,7 @@ TypeInfo { name: "oldPath", is_optional: false, + is_list: false, description: Some( "The old path of the torrent", ), @@ -2738,6 +2871,7 @@ TypeInfo { name: "newPath", is_optional: false, + is_list: false, description: Some( "The new path to use for the file", ), @@ -2762,6 +2896,7 @@ TypeInfo { name: "hash", is_optional: false, + is_list: false, description: Some( "The hash of the torrent", ), @@ -2771,6 +2906,7 @@ TypeInfo { name: "oldPath", is_optional: false, + is_list: false, description: Some( "The old path of the torrent", ), @@ -2780,6 +2916,7 @@ TypeInfo { name: "newPath", is_optional: false, + is_list: false, description: Some( "The new path to use for the file", ), @@ -2813,6 +2950,7 @@ TypeInfo { name: "path", is_optional: false, + is_list: false, description: Some( "Full path of added folder (e.g. \"The Pirate Bay\\Top100\")", ), @@ -2837,6 +2975,7 @@ TypeInfo { name: "url", is_optional: false, + is_list: false, description: Some( "URL of RSS feed (e.g. \"[http://thepiratebay.org/rss//top100/200](http://thepiratebay.org/rss//top100/200)\")", ), @@ -2846,6 +2985,7 @@ TypeInfo { name: "path", is_optional: true, + is_list: false, description: Some( "Full path of added folder (e.g. \"The Pirate Bay\\Top100\\Video\")", ), @@ -2870,6 +3010,7 @@ TypeInfo { name: "path", is_optional: false, + is_list: false, description: Some( "Full path of removed item (e.g. \"The Pirate Bay\\Top100\")", ), @@ -2894,6 +3035,7 @@ TypeInfo { name: "itemPath", is_optional: false, + is_list: false, description: Some( "Current full path of item (e.g. \"The Pirate Bay\\Top100\")", ), @@ -2903,6 +3045,7 @@ TypeInfo { name: "destPath", is_optional: false, + is_list: false, description: Some( "New full path of item (e.g. \"The Pirate Bay\")", ), @@ -2927,6 +3070,7 @@ TypeInfo { name: "withData", is_optional: true, + is_list: false, description: Some( "True if you need current feed articles", ), @@ -2951,6 +3095,7 @@ TypeInfo { name: "itemPath", is_optional: false, + is_list: false, description: Some( "Current full path of item (e.g. \"The Pirate Bay\\Top100\")", ), @@ -2960,6 +3105,7 @@ TypeInfo { name: "articleId", is_optional: true, + is_list: false, description: Some( "ID of article", ), @@ -2984,6 +3130,7 @@ TypeInfo { name: "itemPath", is_optional: false, + is_list: false, description: Some( "Current full path of item (e.g. \"The Pirate Bay\\Top100\")", ), @@ -3008,6 +3155,7 @@ TypeInfo { name: "ruleName", is_optional: false, + is_list: false, description: Some( "Rule name (e.g. \"Punisher\")", ), @@ -3017,6 +3165,7 @@ TypeInfo { name: "ruleDef", is_optional: false, + is_list: false, description: Some( "JSON encoded rule definition", ), @@ -3041,6 +3190,7 @@ TypeInfo { name: "ruleName", is_optional: false, + is_list: false, description: Some( "Rule name (e.g. \"Punisher\")", ), @@ -3050,6 +3200,7 @@ TypeInfo { name: "newRuleName", is_optional: false, + is_list: false, description: Some( "New rule name (e.g. \"The Punisher\")", ), @@ -3074,6 +3225,7 @@ TypeInfo { name: "ruleName", is_optional: false, + is_list: false, description: Some( "Rule name (e.g. \"Punisher\")", ), @@ -3125,6 +3277,7 @@ TypeInfo { name: "pattern", is_optional: false, + is_list: false, description: Some( "Pattern to search for (e.g. \"Ubuntu 18.04\")", ), @@ -3134,6 +3287,7 @@ TypeInfo { name: "plugins", is_optional: false, + is_list: false, description: Some( "Plugins to use for searching (e.g. \"legittorrents\"). Supports multiple plugins separated by \\", ), @@ -3143,6 +3297,7 @@ TypeInfo { name: "category", is_optional: false, + is_list: false, description: Some( "Categories to limit your search to (e.g. \"legittorrents\"). Available categories depend on the specified plugins. Also supports all", ), @@ -3158,6 +3313,7 @@ TypeInfo { name: "id", is_optional: false, + is_list: false, description: Some( "ID of the search job", ), @@ -3182,6 +3338,7 @@ TypeInfo { name: "id", is_optional: false, + is_list: false, description: Some( "ID of the search job", ), @@ -3208,6 +3365,7 @@ TypeInfo { name: "id", is_optional: true, + is_list: false, description: Some( "ID of the search job. If not specified, all search jobs are returned", ), @@ -3223,6 +3381,7 @@ TypeInfo { name: "id", is_optional: false, + is_list: false, description: Some( "ID of the search job", ), @@ -3232,6 +3391,7 @@ TypeInfo { name: "status", is_optional: false, + is_list: false, description: Some( "Current status of the search job (either Running or Stopped)", ), @@ -3241,6 +3401,7 @@ TypeInfo { name: "total", is_optional: false, + is_list: false, description: Some( "Total number of results. If the status is Running this number may contineu to increase", ), @@ -3267,6 +3428,7 @@ TypeInfo { name: "id", is_optional: false, + is_list: false, description: Some( "ID of the search job", ), @@ -3276,6 +3438,7 @@ TypeInfo { name: "limit", is_optional: true, + is_list: false, description: Some( "max number of results to return. 0 or negative means no limit", ), @@ -3285,6 +3448,7 @@ TypeInfo { name: "offset", is_optional: true, + is_list: false, description: Some( "result to start at. A negative number means count backwards (e.g. -2 returns the 2 most recent results)", ), @@ -3301,6 +3465,7 @@ TypeInfo { name: "descrLink", is_optional: false, + is_list: false, description: Some( "URL of the torrent's description page", ), @@ -3310,6 +3475,7 @@ TypeInfo { name: "fileName", is_optional: false, + is_list: false, description: Some( "Name of the file", ), @@ -3319,6 +3485,7 @@ TypeInfo { name: "fileSize", is_optional: false, + is_list: false, description: Some( "Size of the file in Bytes", ), @@ -3328,6 +3495,7 @@ TypeInfo { name: "fileUrl", is_optional: false, + is_list: false, description: Some( "Torrent download link (usually either .torrent file or magnet link)", ), @@ -3337,6 +3505,7 @@ TypeInfo { name: "nbLeechers", is_optional: false, + is_list: false, description: Some( "Number of leechers", ), @@ -3346,6 +3515,7 @@ TypeInfo { name: "nbSeeders", is_optional: false, + is_list: false, description: Some( "Number of seeders", ), @@ -3355,6 +3525,7 @@ TypeInfo { name: "siteUrl", is_optional: false, + is_list: false, description: Some( "URL of the torrent site", ), @@ -3371,6 +3542,7 @@ type_info: TypeInfo { name: "results", is_optional: false, + is_list: false, description: Some( "Array of result objects- see table below", ), @@ -3382,6 +3554,7 @@ TypeInfo { name: "status", is_optional: false, + is_list: false, description: Some( "Current status of the search job (either Running or Stopped)", ), @@ -3391,6 +3564,7 @@ TypeInfo { name: "total", is_optional: false, + is_list: false, description: Some( "Total number of results. If the status is Running this number may continue to increase", ), @@ -3415,6 +3589,7 @@ TypeInfo { name: "id", is_optional: false, + is_list: false, description: Some( "ID of the search job", ), @@ -3441,6 +3616,7 @@ TypeInfo { name: "enabled", is_optional: false, + is_list: false, description: Some( "Whether the plugin is enabled", ), @@ -3450,6 +3626,7 @@ TypeInfo { name: "fullName", is_optional: false, + is_list: false, description: Some( "Full name of the plugin", ), @@ -3459,6 +3636,7 @@ TypeInfo { name: "name", is_optional: false, + is_list: false, description: Some( "Short name of the plugin", ), @@ -3468,6 +3646,7 @@ TypeInfo { name: "supportedCategories", is_optional: false, + is_list: false, description: Some( "List of category objects", ), @@ -3477,6 +3656,7 @@ TypeInfo { name: "url", is_optional: false, + is_list: false, description: Some( "URL of the torrent site", ), @@ -3486,6 +3666,7 @@ TypeInfo { name: "version", is_optional: false, + is_list: false, description: Some( "Installed version of the plugin", ), @@ -3510,6 +3691,7 @@ TypeInfo { name: "sources", is_optional: false, + is_list: false, description: Some( "Url or file path of the plugin to install (e.g. \"[https://raw.githubusercontent.com/qbittorrent/search-plugins/master/nova3/engines/legittorrents.py](https://raw.githubusercontent.com/qbittorrent/search-plugins/master/nova3/engines/legittorrents.py)\"). Supports multiple sources separated by \\", ), @@ -3534,6 +3716,7 @@ TypeInfo { name: "names", is_optional: false, + is_list: false, description: Some( "Name of the plugin to uninstall (e.g. \"legittorrents\"). Supports multiple names separated by \\", ), @@ -3558,6 +3741,7 @@ TypeInfo { name: "names", is_optional: false, + is_list: false, description: Some( "Name of the plugin to enable/disable (e.g. \"legittorrents\"). Supports multiple names separated by \\", ), @@ -3567,6 +3751,7 @@ TypeInfo { name: "enable", is_optional: false, + is_list: false, description: Some( "Whether the plugins should be enabled", ), diff --git a/qbittorrent-web-api-gen/src/generate/group/mod.rs b/qbittorrent-web-api-gen/src/generate/group/mod.rs index 5a392eb..454c165 100644 --- a/qbittorrent-web-api-gen/src/generate/group/mod.rs +++ b/qbittorrent-web-api-gen/src/generate/group/mod.rs @@ -156,7 +156,7 @@ impl types::Type { &self.get_type_info().description, quote! { #[serde(rename = #orig_name)] - #name_snake: #type_name + pub #name_snake: #type_name }, ) } @@ -223,6 +223,69 @@ impl<'a> GroupMethod<'a> { Self { group, method } } + fn generate_method(&self) -> TokenStream { + let method_name = self.method.name_snake(); + let structs = self.method.structs(); + let enums = self.method.enums(); + let builder = self.generate_request_builder(); + let response_struct = self.generate_response_struct(); + let request_method = self.generate_request_method(); + + quote! { + pub mod #method_name { + #structs + #enums + #builder + #response_struct + #request_method + } + } + } + + fn generate_request_method(&self) -> TokenStream { + let method_name = self.method.name_snake(); + + let parameters = self + .method + .types + .mandatory_params() + .iter() + .map(|param| param.to_parameter()) + .collect(); + + let form_builder = self.mandatory_parameters_as_form_builder(); + + let method_impl = if self.method.types.optional_parameters().is_empty() { + self.generate_send_method( + &method_name, + parameters, + quote! { self.auth }, + quote! { form }, + quote! { + let form = reqwest::multipart::Form::new(); + #form_builder + }, + ) + } else { + quote! { + pub fn #method_name(&self, #(#parameters),*) -> Builder<'_> { + let form = reqwest::multipart::Form::new(); + #form_builder + Builder { group: self, form } + } + } + }; + + let group_struct_name = self.group.struct_name(); + let method_impl_with_docs = util::add_docs(&self.method.description, method_impl); + + quote! { + impl<'a> super::#group_struct_name<'a> { + #method_impl_with_docs + } + } + } + fn generate_response_struct(&self) -> TokenStream { let response = match self.method.types.response() { Some(res) => res, @@ -239,20 +302,26 @@ impl<'a> GroupMethod<'a> { } } - fn generate_optional_builder(&self) -> TokenStream { - let optional_params = match self.method.types.optional_parameters() { - Some(params) => params, - None => return quote! {}, - }; + /// Returns a TokenStream containing a request builder if there are optional + /// parameters, otherwise an empty TokenStream is returned. + fn generate_request_builder(&self) -> TokenStream { + let optional_params = self.method.types.optional_parameters(); + if optional_params.is_empty() { + return quote! {}; + } let builder_methods = optional_params .iter() .map(|param| param.generate_optional_builder_method_with_docs()); let group_name = self.group.struct_name(); - let mandatory_params = self.mandatory_parameters(); - let mandatory_param_form_builder = self.mandatory_parameters_as_form_builder(); - let send_method = self.generate_optional_builder_send_method(); + let send_method = self.generate_send_method( + &util::to_ident("send"), + vec![], + quote! { self.group.auth }, + quote! { self.form }, + quote! {}, + ); quote! { pub struct Builder<'a> { @@ -261,104 +330,55 @@ impl<'a> GroupMethod<'a> { } impl<'a> Builder<'a> { - pub fn new(group: &'a super::#group_name, #mandatory_params) -> Self { - let form = reqwest::multipart::Form::new(); - #mandatory_param_form_builder - Self { group, form } - } - #send_method - #(#builder_methods)* } } } - fn generate_optional_builder_send_method(&self) -> TokenStream { + fn generate_send_method( + &self, + method_name: &Ident, + parameters: Vec, + auth_access: TokenStream, + form_access: TokenStream, + form_factory: TokenStream, + ) -> TokenStream { let method_url = format!("/api/v2/{}/{}", self.group.url, self.method.url); - match self.method.types.response() { - Some(_) => { - quote! { - pub async fn send(self) -> super::super::Result { - let res = self - .group - .auth - .authenticated_client(#method_url) - .multipart(self.form) - .send() - .await? - .json::() - .await?; - - Ok(res) - } - } - } - None => { - quote! { - pub async fn send(self) -> super::super::Result { - let res = self - .group - .auth - .authenticated_client(#method_url) - .multipart(self.form) - .send() - .await? - .text() - .await?; - - Ok(res) - } - } - } - } - } - - fn mandatory_parameters(&self) -> TokenStream { - let mandatory_params = match self.method.types.mandatory_params() { - Some(p) => p, - None => return quote! {}, + let (response_type, response_parse) = match self.method.types.response() { + Some(_) => (quote! { Response }, quote! { .json::() }), + None => (quote! { String }, quote! { .text() }), }; - let params = mandatory_params.iter().map(|param| param.to_parameter()); - quote! { - #(#params),* + pub async fn #method_name(self, #(#parameters),*) -> super::super::Result<#response_type> { + #form_factory + let res = #auth_access + .authenticated_client(#method_url) + .multipart(#form_access) + .send() + .await? + #response_parse + .await?; + + Ok(res) + } } } fn mandatory_parameters_as_form_builder(&self) -> TokenStream { - let mandatory_params = match self.method.types.mandatory_params() { - Some(p) => p, - None => return quote! {}, - }; - - let builder = mandatory_params - .iter() + let builder = self + .method + .types + .mandatory_params() + .into_iter() .map(|param| param.generate_form_builder(quote! { form })); quote! { #(let #builder)* } } - - fn generate_method(&self) -> TokenStream { - let method_name = self.method.name_snake(); - let structs = self.method.structs(); - let enums = self.method.enums(); - let builder = self.generate_optional_builder(); - let response_struct = self.generate_response_struct(); - - quote! { - pub mod #method_name { - #structs - #enums - #builder - #response_struct - } - } - } } impl types::Type { diff --git a/qbittorrent-web-api-gen/src/parser/group/method/method_tests/search_result.check b/qbittorrent-web-api-gen/src/parser/group/method/method_tests/search_result.check index 1f2c06b..48fccea 100644 --- a/qbittorrent-web-api-gen/src/parser/group/method/method_tests/search_result.check +++ b/qbittorrent-web-api-gen/src/parser/group/method/method_tests/search_result.check @@ -13,6 +13,7 @@ ApiMethod { TypeInfo { name: "id", is_optional: false, + is_list: false, description: Some( "ID of the search job", ), @@ -22,6 +23,7 @@ ApiMethod { TypeInfo { name: "limit", is_optional: true, + is_list: false, description: Some( "max number of results to return. 0 or negative means no limit", ), @@ -31,6 +33,7 @@ ApiMethod { TypeInfo { name: "offset", is_optional: true, + is_list: false, description: Some( "result to start at. A negative number means count backwards (e.g. -2 returns the 2 most recent results)", ), @@ -47,6 +50,7 @@ ApiMethod { TypeInfo { name: "descrLink", is_optional: false, + is_list: false, description: Some( "URL of the torrent's description page", ), @@ -56,6 +60,7 @@ ApiMethod { TypeInfo { name: "fileName", is_optional: false, + is_list: false, description: Some( "Name of the file", ), @@ -65,6 +70,7 @@ ApiMethod { TypeInfo { name: "fileSize", is_optional: false, + is_list: false, description: Some( "Size of the file in Bytes", ), @@ -74,6 +80,7 @@ ApiMethod { TypeInfo { name: "fileUrl", is_optional: false, + is_list: false, description: Some( "Torrent download link (usually either .torrent file or magnet link)", ), @@ -83,6 +90,7 @@ ApiMethod { TypeInfo { name: "nbLeechers", is_optional: false, + is_list: false, description: Some( "Number of leechers", ), @@ -92,6 +100,7 @@ ApiMethod { TypeInfo { name: "nbSeeders", is_optional: false, + is_list: false, description: Some( "Number of seeders", ), @@ -101,6 +110,7 @@ ApiMethod { TypeInfo { name: "siteUrl", is_optional: false, + is_list: false, description: Some( "URL of the torrent site", ), @@ -117,6 +127,7 @@ ApiMethod { type_info: TypeInfo { name: "results", is_optional: false, + is_list: false, description: Some( "Array of result objects- see table below", ), @@ -128,6 +139,7 @@ ApiMethod { TypeInfo { name: "status", is_optional: false, + is_list: false, description: Some( "Current status of the search job (either Running or Stopped)", ), @@ -137,6 +149,7 @@ ApiMethod { TypeInfo { name: "total", is_optional: false, + is_list: false, description: Some( "Total number of results. If the status is Running this number may continue to increase", ), diff --git a/qbittorrent-web-api-gen/src/parser/group/method/mod.rs b/qbittorrent-web-api-gen/src/parser/group/method/mod.rs index 49d96ec..4a50f62 100644 --- a/qbittorrent-web-api-gen/src/parser/group/method/mod.rs +++ b/qbittorrent-web-api-gen/src/parser/group/method/mod.rs @@ -27,21 +27,30 @@ impl CompositeTypes { } } - pub fn parameters(&self) -> Option<&Vec> { - self.composite_types.iter().find_map(|type_| match type_ { - CompositeType::Parameters(p) => Some(&p.types), - _ => None, - }) + pub fn parameters(&self) -> Vec<&types::Type> { + self.composite_types + .iter() + .find_map(|type_| match type_ { + CompositeType::Parameters(p) => Some(p.types.iter().collect()), + _ => None, + }) + .unwrap_or_default() } - pub fn optional_parameters(&self) -> Option> { + pub fn optional_parameters(&self) -> Vec<&types::Type> { self.parameters() - .map(|params| params.iter().filter(|param| param.is_optional()).collect()) + .iter() + .filter(|param| param.is_optional()) + .copied() + .collect() } - pub fn mandatory_params(&self) -> Option> { + pub fn mandatory_params(&self) -> Vec<&types::Type> { self.parameters() - .map(|params| params.iter().filter(|param| !param.is_optional()).collect()) + .iter() + .filter(|param| !param.is_optional()) + .copied() + .collect() } pub fn response(&self) -> Option<&Vec> { @@ -386,11 +395,6 @@ mod tests { ".check" ); - // prevent user from accidentally leaving the current macro in a test - if Path::new(file).exists() { - panic!("Test case already exists: {file}"); - } - fs::write(file, api_method_as_str).unwrap(); fs::write(tree_file, tree_as_str).unwrap(); }; diff --git a/qbittorrent-web-api-gen/src/types.rs b/qbittorrent-web-api-gen/src/types.rs index b56561f..498498c 100644 --- a/qbittorrent-web-api-gen/src/types.rs +++ b/qbittorrent-web-api-gen/src/types.rs @@ -16,16 +16,16 @@ pub struct TypeDescription { pub struct TypeInfo { pub name: String, pub is_optional: bool, - // is_list: bool, + pub is_list: bool, pub description: Option, } impl TypeInfo { - pub fn new(name: &str, is_optional: bool, description: Option) -> Self { + pub fn new(name: &str, is_optional: bool, is_list: bool, description: Option) -> Self { Self { name: name.into(), is_optional, - // is_list, + is_list, description, } } @@ -74,10 +74,6 @@ impl Type { } } - // pub fn is_list(&self) -> bool { - // self.get_type_info().is_list || matches!(self, Type::StringArray(_)) - // } - pub fn to_borrowed_type(&self) -> String { match self { Type::Number(_) => "i32".into(), @@ -116,7 +112,12 @@ impl Type { .trim(); let is_optional = name.contains(OPTIONAL); - let create_type_info = || TypeInfo::new(type_name, is_optional, description.clone()); + let is_list = description + .clone() + .map(|desc| desc.contains("array")) + .unwrap_or(false); + let create_type_info = + || TypeInfo::new(type_name, is_optional, is_list, description.clone()); let create_object_type = |name: &str| { Some(Type::Object(Object { @@ -126,6 +127,7 @@ impl Type { }; match type_as_str { + "raw" => None, "bool" => Some(Type::Bool(create_type_info())), "integer" | "number" | "int" => Some(Type::Number(create_type_info())), "string" => Some(Type::String(create_type_info())), From ab816e14b18a1521315c319aa3ea572524d75082 Mon Sep 17 00:00:00 2001 From: Joel Wachsler Date: Fri, 22 Jul 2022 22:22:57 +0000 Subject: [PATCH 42/47] Support for list return --- qbittorrent-web-api-gen/groups.txt | 924 ++++++++++-------- .../src/generate/group/mod.rs | 23 +- .../method/method_tests/array_field.check | 26 + .../group/method/method_tests/array_field.md | 9 + .../method/method_tests/array_field.tree | 52 + .../method/method_tests/array_result.check | 26 + .../group/method/method_tests/array_result.md | 9 + .../method/method_tests/array_result.tree | 52 + .../method/method_tests/search_result.check | 56 +- .../src/parser/group/method/mod.rs | 21 +- qbittorrent-web-api-gen/src/types.rs | 29 +- .../tests/access_impl_types.rs | 2 +- 12 files changed, 764 insertions(+), 465 deletions(-) create mode 100644 qbittorrent-web-api-gen/src/parser/group/method/method_tests/array_field.check create mode 100644 qbittorrent-web-api-gen/src/parser/group/method/method_tests/array_field.md create mode 100644 qbittorrent-web-api-gen/src/parser/group/method/method_tests/array_field.tree create mode 100644 qbittorrent-web-api-gen/src/parser/group/method/method_tests/array_result.check create mode 100644 qbittorrent-web-api-gen/src/parser/group/method/method_tests/array_result.md create mode 100644 qbittorrent-web-api-gen/src/parser/group/method/method_tests/array_result.tree diff --git a/qbittorrent-web-api-gen/groups.txt b/qbittorrent-web-api-gen/groups.txt index 8edc7b7..0cf22a1 100644 --- a/qbittorrent-web-api-gen/groups.txt +++ b/qbittorrent-web-api-gen/groups.txt @@ -16,24 +16,25 @@ String( TypeInfo { name: "username", - is_optional: false, - is_list: false, description: Some( "Username used to access the WebUI", ), + is_optional: false, + is_list: false, }, ), String( TypeInfo { name: "password", - is_optional: false, - is_list: false, description: Some( "Password used to access the WebUI", ), + is_optional: false, + is_list: false, }, ), ], + is_list: false, }, ), ], @@ -90,54 +91,55 @@ String( TypeInfo { name: "qt", - is_optional: false, - is_list: false, description: Some( "QT version", ), + is_optional: false, + is_list: false, }, ), String( TypeInfo { name: "libtorrent", - is_optional: false, - is_list: false, description: Some( "libtorrent version", ), + is_optional: false, + is_list: false, }, ), String( TypeInfo { name: "boost", - is_optional: false, - is_list: false, description: Some( "Boost version", ), + is_optional: false, + is_list: false, }, ), String( TypeInfo { name: "openssl", - is_optional: false, - is_list: false, description: Some( "OpenSSL version", ), + is_optional: false, + is_list: false, }, ), Number( TypeInfo { name: "bitness", - is_optional: false, - is_list: false, description: Some( "Application bitness (e.g. 64-bit)", ), + is_optional: false, + is_list: false, }, ), ], + is_list: false, }, ), ], @@ -527,54 +529,55 @@ Bool( TypeInfo { name: "normal", - is_optional: true, - is_list: false, description: Some( "Include normal messages (default: true)", ), + is_optional: true, + is_list: false, }, ), Bool( TypeInfo { name: "info", - is_optional: true, - is_list: false, description: Some( "Include info messages (default: true)", ), + is_optional: true, + is_list: false, }, ), Bool( TypeInfo { name: "warning", - is_optional: true, - is_list: false, description: Some( "Include warning messages (default: true)", ), + is_optional: true, + is_list: false, }, ), Bool( TypeInfo { name: "critical", - is_optional: true, - is_list: false, description: Some( "Include critical messages (default: true)", ), + is_optional: true, + is_list: false, }, ), Number( TypeInfo { name: "last_known_id", - is_optional: true, - is_list: false, description: Some( "Exclude messages with \"message id\" <= last_known_id (default: -1)", ), + is_optional: true, + is_list: false, }, ), ], + is_list: false, }, ), ], @@ -594,14 +597,15 @@ Number( TypeInfo { name: "last_known_id", - is_optional: true, - is_list: false, description: Some( "Exclude messages with \"message id\" <= last_known_id (default: -1)", ), + is_optional: true, + is_list: false, }, ), ], + is_list: false, }, ), ], @@ -630,14 +634,15 @@ Number( TypeInfo { name: "rid", - is_optional: false, - is_list: false, description: Some( "Response ID. If not provided, rid=0 will be assumed. If the given rid is different from the one of last server reply, full_update will be true (see the server reply details for more info)", ), + is_optional: false, + is_list: false, }, ), ], + is_list: false, }, ), Response( @@ -646,103 +651,116 @@ Number( TypeInfo { name: "rid", - is_optional: false, - is_list: false, description: Some( "Response ID", ), + is_optional: false, + is_list: false, }, ), Bool( TypeInfo { name: "full_update", - is_optional: false, - is_list: false, description: Some( "Whether the response contains all the data or partial data", ), + is_optional: false, + is_list: false, }, ), Object( Object { type_info: TypeInfo { name: "torrents", - is_optional: false, - is_list: false, description: Some( "Property: torrent hash, value: same as [torrent list](#get-torrent-list)", ), + is_optional: false, + is_list: false, }, ref_type: "Object", }, ), - StringArray( - TypeInfo { - name: "torrents_removed", - is_optional: false, - is_list: false, - description: Some( - "List of hashes of torrents removed since last request", - ), + Object( + Object { + type_info: TypeInfo { + name: "torrents_removed", + description: Some( + "List of hashes of torrents removed since last request", + ), + is_optional: false, + is_list: true, + }, + ref_type: "", }, ), Object( Object { type_info: TypeInfo { name: "categories", - is_optional: false, - is_list: false, description: Some( "Info for categories added since last request", ), + is_optional: false, + is_list: false, }, ref_type: "Object", }, ), - StringArray( - TypeInfo { - name: "categories_removed", - is_optional: false, - is_list: false, - description: Some( - "List of categories removed since last request", - ), + Object( + Object { + type_info: TypeInfo { + name: "categories_removed", + description: Some( + "List of categories removed since last request", + ), + is_optional: false, + is_list: true, + }, + ref_type: "", }, ), - StringArray( - TypeInfo { - name: "tags", - is_optional: false, - is_list: false, - description: Some( - "List of tags added since last request", - ), + Object( + Object { + type_info: TypeInfo { + name: "tags", + description: Some( + "List of tags added since last request", + ), + is_optional: false, + is_list: true, + }, + ref_type: "", }, ), - StringArray( - TypeInfo { - name: "tags_removed", - is_optional: false, - is_list: false, - description: Some( - "List of tags removed since last request", - ), + Object( + Object { + type_info: TypeInfo { + name: "tags_removed", + description: Some( + "List of tags removed since last request", + ), + is_optional: false, + is_list: true, + }, + ref_type: "", }, ), Object( Object { type_info: TypeInfo { name: "server_state", - is_optional: false, - is_list: false, description: Some( "Global transfer info", ), + is_optional: false, + is_list: false, }, ref_type: "Object", }, ), ], + is_list: false, }, ), ], @@ -762,24 +780,25 @@ String( TypeInfo { name: "hash", - is_optional: false, - is_list: false, description: Some( "Torrent hash", ), + is_optional: false, + is_list: false, }, ), Number( TypeInfo { name: "rid", - is_optional: false, - is_list: false, description: Some( "Response ID. If not provided, rid=0 will be assumed. If the given rid is different from the one of last server reply, full_update will be true (see the server reply details for more info)", ), + is_optional: false, + is_list: false, }, ), ], + is_list: false, }, ), ], @@ -808,84 +827,85 @@ Number( TypeInfo { name: "dl_info_speed", - is_optional: false, - is_list: false, description: Some( "Global download rate (bytes/s)", ), + is_optional: false, + is_list: false, }, ), Number( TypeInfo { name: "dl_info_data", - is_optional: false, - is_list: false, description: Some( "Data downloaded this session (bytes)", ), + is_optional: false, + is_list: false, }, ), Number( TypeInfo { name: "up_info_speed", - is_optional: false, - is_list: false, description: Some( "Global upload rate (bytes/s)", ), + is_optional: false, + is_list: false, }, ), Number( TypeInfo { name: "up_info_data", - is_optional: false, - is_list: false, description: Some( "Data uploaded this session (bytes)", ), + is_optional: false, + is_list: false, }, ), Number( TypeInfo { name: "dl_rate_limit", - is_optional: false, - is_list: false, description: Some( "Download rate limit (bytes/s)", ), + is_optional: false, + is_list: false, }, ), Number( TypeInfo { name: "up_rate_limit", - is_optional: false, - is_list: false, description: Some( "Upload rate limit (bytes/s)", ), + is_optional: false, + is_list: false, }, ), Number( TypeInfo { name: "dht_nodes", - is_optional: false, - is_list: false, description: Some( "DHT nodes connected to", ), + is_optional: false, + is_list: false, }, ), String( TypeInfo { name: "connection_status", - is_optional: false, - is_list: false, description: Some( "Connection status. See possible values here below", ), + is_optional: false, + is_list: false, }, ), ], + is_list: false, }, ), ], @@ -931,14 +951,15 @@ Number( TypeInfo { name: "limit", - is_optional: false, - is_list: false, description: Some( "The global download speed limit to set in bytes/second", ), + is_optional: false, + is_list: false, }, ), ], + is_list: false, }, ), ], @@ -966,14 +987,15 @@ Number( TypeInfo { name: "limit", - is_optional: false, - is_list: false, description: Some( "The global upload speed limit to set in bytes/second", ), + is_optional: false, + is_list: false, }, ), ], + is_list: false, }, ), ], @@ -991,14 +1013,15 @@ String( TypeInfo { name: "peers", - is_optional: false, - is_list: false, description: Some( "The peer to ban, or multiple peers separated by a pipe \\", ), + is_optional: false, + is_list: false, }, ), ], + is_list: false, }, ), ], @@ -1027,84 +1050,85 @@ String( TypeInfo { name: "filter", - is_optional: true, - is_list: false, description: Some( "Filter torrent list by state. Allowed state filters: all, downloading, seeding, completed, paused, active, inactive, resumed, stalled, stalled_uploading, stalled_downloading, errored", ), + is_optional: true, + is_list: false, }, ), String( TypeInfo { name: "category", - is_optional: true, - is_list: false, description: Some( "Get torrents with the given category (empty string means \"without category\"; no \"category\" parameter means \"any category\" <- broken until [#11748](https://github.com/qbittorrent/qBittorrent/issues/11748) is resolved). Remember to URL-encode the category name. For example, My category becomes My%20category", ), + is_optional: true, + is_list: false, }, ), String( TypeInfo { name: "tag", - is_optional: true, - is_list: false, description: Some( "Get torrents with the given tag (empty string means \"without tag\"; no \"tag\" parameter means \"any tag\". Remember to URL-encode the category name. For example, My tag becomes My%20tag", ), + is_optional: true, + is_list: false, }, ), String( TypeInfo { name: "sort", - is_optional: true, - is_list: true, description: Some( "Sort torrents by given key. They can be sorted using any field of the response's JSON array (which are documented below) as the sort key.", ), + is_optional: true, + is_list: true, }, ), Bool( TypeInfo { name: "reverse", - is_optional: true, - is_list: false, description: Some( "Enable reverse sorting. Defaults to false", ), + is_optional: true, + is_list: false, }, ), Number( TypeInfo { name: "limit", - is_optional: true, - is_list: false, description: Some( "Limit the number of torrents returned", ), + is_optional: true, + is_list: false, }, ), Number( TypeInfo { name: "offset", - is_optional: true, - is_list: false, description: Some( "Set offset (if less than 0, offset from end)", ), + is_optional: true, + is_list: false, }, ), String( TypeInfo { name: "hashes", - is_optional: true, - is_list: false, description: Some( "Filter by hashes. Can contain multiple hashes separated by \\", ), + is_optional: true, + is_list: false, }, ), ], + is_list: false, }, ), Enum( @@ -1253,454 +1277,455 @@ Number( TypeInfo { name: "added_on", - is_optional: false, - is_list: false, description: Some( "Time (Unix Epoch) when the torrent was added to the client", ), + is_optional: false, + is_list: false, }, ), Number( TypeInfo { name: "amount_left", - is_optional: false, - is_list: false, description: Some( "Amount of data left to download (bytes)", ), + is_optional: false, + is_list: false, }, ), Bool( TypeInfo { name: "auto_tmm", - is_optional: false, - is_list: false, description: Some( "Whether this torrent is managed by Automatic Torrent Management", ), + is_optional: false, + is_list: false, }, ), Float( TypeInfo { name: "availability", - is_optional: false, - is_list: false, description: Some( "Percentage of file pieces currently available", ), + is_optional: false, + is_list: false, }, ), String( TypeInfo { name: "category", - is_optional: false, - is_list: false, description: Some( "Category of the torrent", ), + is_optional: false, + is_list: false, }, ), Number( TypeInfo { name: "completed", - is_optional: false, - is_list: false, description: Some( "Amount of transfer data completed (bytes)", ), + is_optional: false, + is_list: false, }, ), Number( TypeInfo { name: "completion_on", - is_optional: false, - is_list: false, description: Some( "Time (Unix Epoch) when the torrent completed", ), + is_optional: false, + is_list: false, }, ), String( TypeInfo { name: "content_path", - is_optional: false, - is_list: false, description: Some( "Absolute path of torrent content (root path for multifile torrents, absolute file path for singlefile torrents)", ), + is_optional: false, + is_list: false, }, ), Number( TypeInfo { name: "dl_limit", - is_optional: false, - is_list: false, description: Some( "Torrent download speed limit (bytes/s). -1 if ulimited.", ), + is_optional: false, + is_list: false, }, ), Number( TypeInfo { name: "dlspeed", - is_optional: false, - is_list: false, description: Some( "Torrent download speed (bytes/s)", ), + is_optional: false, + is_list: false, }, ), Number( TypeInfo { name: "downloaded", - is_optional: false, - is_list: false, description: Some( "Amount of data downloaded", ), + is_optional: false, + is_list: false, }, ), Number( TypeInfo { name: "downloaded_session", - is_optional: false, - is_list: false, description: Some( "Amount of data downloaded this session", ), + is_optional: false, + is_list: false, }, ), Number( TypeInfo { name: "eta", - is_optional: false, - is_list: false, description: Some( "Torrent ETA (seconds)", ), + is_optional: false, + is_list: false, }, ), Bool( TypeInfo { name: "f_l_piece_prio", - is_optional: false, - is_list: false, description: Some( "True if first last piece are prioritized", ), + is_optional: false, + is_list: false, }, ), Bool( TypeInfo { name: "force_start", - is_optional: false, - is_list: false, description: Some( "True if force start is enabled for this torrent", ), + is_optional: false, + is_list: false, }, ), String( TypeInfo { name: "hash", - is_optional: false, - is_list: false, description: Some( "Torrent hash", ), + is_optional: false, + is_list: false, }, ), Number( TypeInfo { name: "last_activity", - is_optional: false, - is_list: false, description: Some( "Last time (Unix Epoch) when a chunk was downloaded/uploaded", ), + is_optional: false, + is_list: false, }, ), String( TypeInfo { name: "magnet_uri", - is_optional: false, - is_list: false, description: Some( "Magnet URI corresponding to this torrent", ), + is_optional: false, + is_list: false, }, ), Float( TypeInfo { name: "max_ratio", - is_optional: false, - is_list: false, description: Some( "Maximum share ratio until torrent is stopped from seeding/uploading", ), + is_optional: false, + is_list: false, }, ), Number( TypeInfo { name: "max_seeding_time", - is_optional: false, - is_list: false, description: Some( "Maximum seeding time (seconds) until torrent is stopped from seeding", ), + is_optional: false, + is_list: false, }, ), String( TypeInfo { name: "name", - is_optional: false, - is_list: false, description: Some( "Torrent name", ), + is_optional: false, + is_list: false, }, ), Number( TypeInfo { name: "num_complete", - is_optional: false, - is_list: false, description: Some( "Number of seeds in the swarm", ), + is_optional: false, + is_list: false, }, ), Number( TypeInfo { name: "num_incomplete", - is_optional: false, - is_list: false, description: Some( "Number of leechers in the swarm", ), + is_optional: false, + is_list: false, }, ), Number( TypeInfo { name: "num_leechs", - is_optional: false, - is_list: false, description: Some( "Number of leechers connected to", ), + is_optional: false, + is_list: false, }, ), Number( TypeInfo { name: "num_seeds", - is_optional: false, - is_list: false, description: Some( "Number of seeds connected to", ), + is_optional: false, + is_list: false, }, ), Number( TypeInfo { name: "priority", - is_optional: false, - is_list: false, description: Some( "Torrent priority. Returns -1 if queuing is disabled or torrent is in seed mode", ), + is_optional: false, + is_list: false, }, ), Float( TypeInfo { name: "progress", - is_optional: false, - is_list: false, description: Some( "Torrent progress (percentage/100)", ), + is_optional: false, + is_list: false, }, ), Float( TypeInfo { name: "ratio", - is_optional: false, - is_list: false, description: Some( "Torrent share ratio. Max ratio value: 9999.", ), + is_optional: false, + is_list: false, }, ), Float( TypeInfo { name: "ratio_limit", - is_optional: false, - is_list: false, description: Some( "TODO (what is different from max_ratio?)", ), + is_optional: false, + is_list: false, }, ), String( TypeInfo { name: "save_path", - is_optional: false, - is_list: false, description: Some( "Path where this torrent's data is stored", ), + is_optional: false, + is_list: false, }, ), Number( TypeInfo { name: "seeding_time", - is_optional: false, - is_list: false, description: Some( "Torrent elapsed time while complete (seconds)", ), + is_optional: false, + is_list: false, }, ), Number( TypeInfo { name: "seeding_time_limit", - is_optional: false, - is_list: false, description: Some( "TODO (what is different from max_seeding_time?) seeding_time_limit is a per torrent setting, when Automatic Torrent Management is disabled, furthermore then max_seeding_time is set to seeding_time_limit for this torrent. If Automatic Torrent Management is enabled, the value is -2. And if max_seeding_time is unset it have a default value -1.", ), + is_optional: false, + is_list: false, }, ), Number( TypeInfo { name: "seen_complete", - is_optional: false, - is_list: false, description: Some( "Time (Unix Epoch) when this torrent was last seen complete", ), + is_optional: false, + is_list: false, }, ), Bool( TypeInfo { name: "seq_dl", - is_optional: false, - is_list: false, description: Some( "True if sequential download is enabled", ), + is_optional: false, + is_list: false, }, ), Number( TypeInfo { name: "size", - is_optional: false, - is_list: false, description: Some( "Total size (bytes) of files selected for download", ), + is_optional: false, + is_list: false, }, ), String( TypeInfo { name: "state", - is_optional: false, - is_list: false, description: Some( "Torrent state. See table here below for the possible values", ), + is_optional: false, + is_list: false, }, ), Bool( TypeInfo { name: "super_seeding", - is_optional: false, - is_list: false, description: Some( "True if super seeding is enabled", ), + is_optional: false, + is_list: false, }, ), String( TypeInfo { name: "tags", - is_optional: false, - is_list: false, description: Some( "Comma-concatenated tag list of the torrent", ), + is_optional: false, + is_list: false, }, ), Number( TypeInfo { name: "time_active", - is_optional: false, - is_list: false, description: Some( "Total active time (seconds)", ), + is_optional: false, + is_list: false, }, ), Number( TypeInfo { name: "total_size", - is_optional: false, - is_list: false, description: Some( "Total size (bytes) of all file in this torrent (including unselected ones)", ), + is_optional: false, + is_list: false, }, ), String( TypeInfo { name: "tracker", - is_optional: false, - is_list: false, description: Some( "The first tracker with working status. Returns empty string if no tracker is working.", ), + is_optional: false, + is_list: false, }, ), Number( TypeInfo { name: "up_limit", - is_optional: false, - is_list: false, description: Some( "Torrent upload speed limit (bytes/s). -1 if ulimited.", ), + is_optional: false, + is_list: false, }, ), Number( TypeInfo { name: "uploaded", - is_optional: false, - is_list: false, description: Some( "Amount of data uploaded", ), + is_optional: false, + is_list: false, }, ), Number( TypeInfo { name: "uploaded_session", - is_optional: false, - is_list: false, description: Some( "Amount of data uploaded this session", ), + is_optional: false, + is_list: false, }, ), Number( TypeInfo { name: "upspeed", - is_optional: false, - is_list: false, description: Some( "Torrent upload speed (bytes/s)", ), + is_optional: false, + is_list: false, }, ), ], + is_list: true, }, ), ], @@ -1720,14 +1745,15 @@ String( TypeInfo { name: "hash", - is_optional: false, - is_list: false, description: Some( "The hash of the torrent you want to get the generic properties of", ), + is_optional: false, + is_list: false, }, ), ], + is_list: false, }, ), ], @@ -1747,14 +1773,15 @@ String( TypeInfo { name: "hash", - is_optional: false, - is_list: false, description: Some( "The hash of the torrent you want to get the trackers of", ), + is_optional: false, + is_list: false, }, ), ], + is_list: false, }, ), Enum( @@ -1805,84 +1832,85 @@ String( TypeInfo { name: "url", - is_optional: false, - is_list: false, description: Some( "Tracker url", ), + is_optional: false, + is_list: false, }, ), Number( TypeInfo { name: "status", - is_optional: false, - is_list: false, description: Some( "Tracker status. See the table below for possible values", ), + is_optional: false, + is_list: false, }, ), Number( TypeInfo { name: "tier", - is_optional: false, - is_list: false, description: Some( "Tracker priority tier. Lower tier trackers are tried before higher tiers. Tier numbers are valid when >= 0, < 0 is used as placeholder when tier does not exist for special entries (such as DHT).", ), + is_optional: false, + is_list: false, }, ), Number( TypeInfo { name: "num_peers", - is_optional: false, - is_list: false, description: Some( "Number of peers for current torrent, as reported by the tracker", ), + is_optional: false, + is_list: false, }, ), Number( TypeInfo { name: "num_seeds", - is_optional: false, - is_list: false, description: Some( "Number of seeds for current torrent, asreported by the tracker", ), + is_optional: false, + is_list: false, }, ), Number( TypeInfo { name: "num_leeches", - is_optional: false, - is_list: false, description: Some( "Number of leeches for current torrent, as reported by the tracker", ), + is_optional: false, + is_list: false, }, ), Number( TypeInfo { name: "num_downloaded", - is_optional: false, - is_list: false, description: Some( "Number of completed downlods for current torrent, as reported by the tracker", ), + is_optional: false, + is_list: false, }, ), String( TypeInfo { name: "msg", - is_optional: false, - is_list: false, description: Some( "Tracker message (there is no way of knowing what this message is - it's up to tracker admins)", ), + is_optional: false, + is_list: false, }, ), ], + is_list: true, }, ), ], @@ -1902,14 +1930,15 @@ String( TypeInfo { name: "hash", - is_optional: false, - is_list: false, description: Some( "The hash of the torrent you want to get the webseeds of", ), + is_optional: false, + is_list: false, }, ), ], + is_list: false, }, ), Response( @@ -1918,14 +1947,15 @@ String( TypeInfo { name: "url", - is_optional: false, - is_list: false, description: Some( "URL of the web seed", ), + is_optional: false, + is_list: false, }, ), ], + is_list: true, }, ), ], @@ -1945,24 +1975,25 @@ String( TypeInfo { name: "hash", - is_optional: false, - is_list: false, description: Some( "The hash of the torrent you want to get the contents of", ), + is_optional: false, + is_list: false, }, ), String( TypeInfo { name: "indexes", - is_optional: true, - is_list: false, description: Some( "The indexes of the files you want to retrieve. indexes can contain multiple values separated by \\", ), + is_optional: true, + is_list: false, }, ), ], + is_list: false, }, ), Enum( @@ -2017,14 +2048,15 @@ String( TypeInfo { name: "hash", - is_optional: false, - is_list: false, description: Some( "The hash of the torrent you want to get the pieces' states of", ), + is_optional: false, + is_list: false, }, ), ], + is_list: false, }, ), ], @@ -2044,14 +2076,15 @@ String( TypeInfo { name: "hash", - is_optional: false, - is_list: false, description: Some( "The hash of the torrent you want to get the pieces' hashes of", ), + is_optional: false, + is_list: false, }, ), ], + is_list: false, }, ), ], @@ -2069,14 +2102,15 @@ String( TypeInfo { name: "hashes", - is_optional: false, - is_list: false, description: Some( "The hashes of the torrents you want to pause. hashes can contain multiple hashes separated by \\", ), + is_optional: false, + is_list: false, }, ), ], + is_list: false, }, ), ], @@ -2094,14 +2128,15 @@ String( TypeInfo { name: "hashes", - is_optional: false, - is_list: false, description: Some( "The hashes of the torrents you want to resume. hashes can contain multiple hashes separated by \\", ), + is_optional: false, + is_list: false, }, ), ], + is_list: false, }, ), ], @@ -2119,25 +2154,26 @@ String( TypeInfo { name: "hashes", - is_optional: false, - is_list: false, description: Some( "The hashes of the torrents you want to delete. hashes can contain multiple hashes separated by \\", ), + is_optional: false, + is_list: false, }, ), Object( Object { type_info: TypeInfo { name: "deleteFiles", + description: None, is_optional: false, is_list: false, - description: None, }, ref_type: "If set to true, the downloaded data will also be deleted, otherwise has no effect.", }, ), ], + is_list: false, }, ), ], @@ -2155,14 +2191,15 @@ String( TypeInfo { name: "hashes", - is_optional: false, - is_list: false, description: Some( "The hashes of the torrents you want to recheck. hashes can contain multiple hashes separated by \\", ), + is_optional: false, + is_list: false, }, ), ], + is_list: false, }, ), ], @@ -2180,14 +2217,15 @@ String( TypeInfo { name: "hashes", - is_optional: false, - is_list: false, description: Some( "The hashes of the torrents you want to reannounce. hashes can contain multiple hashes separated by \\", ), + is_optional: false, + is_list: false, }, ), ], + is_list: false, }, ), ], @@ -2205,164 +2243,165 @@ String( TypeInfo { name: "urls", - is_optional: false, - is_list: false, description: Some( "URLs separated with newlines", ), + is_optional: false, + is_list: false, }, ), String( TypeInfo { name: "savepath", - is_optional: true, - is_list: false, description: Some( "Download folder", ), + is_optional: true, + is_list: false, }, ), String( TypeInfo { name: "cookie", - is_optional: true, - is_list: false, description: Some( "Cookie sent to download the .torrent file", ), + is_optional: true, + is_list: false, }, ), String( TypeInfo { name: "category", - is_optional: true, - is_list: false, description: Some( "Category for the torrent", ), + is_optional: true, + is_list: false, }, ), String( TypeInfo { name: "tags", - is_optional: true, - is_list: false, description: Some( "Tags for the torrent, split by ','", ), + is_optional: true, + is_list: false, }, ), String( TypeInfo { name: "skip_checking", - is_optional: true, - is_list: false, description: Some( "Skip hash checking. Possible values are true, false (default)", ), + is_optional: true, + is_list: false, }, ), String( TypeInfo { name: "paused", - is_optional: true, - is_list: false, description: Some( "Add torrents in the paused state. Possible values are true, false (default)", ), + is_optional: true, + is_list: false, }, ), String( TypeInfo { name: "root_folder", - is_optional: true, - is_list: false, description: Some( "Create the root folder. Possible values are true, false, unset (default)", ), + is_optional: true, + is_list: false, }, ), String( TypeInfo { name: "rename", - is_optional: true, - is_list: false, description: Some( "Rename torrent", ), + is_optional: true, + is_list: false, }, ), Number( TypeInfo { name: "upLimit", - is_optional: true, - is_list: false, description: Some( "Set torrent upload speed limit. Unit in bytes/second", ), + is_optional: true, + is_list: false, }, ), Number( TypeInfo { name: "dlLimit", - is_optional: true, - is_list: false, description: Some( "Set torrent download speed limit. Unit in bytes/second", ), + is_optional: true, + is_list: false, }, ), Float( TypeInfo { name: "ratioLimit", - is_optional: true, - is_list: false, description: Some( "Set torrent share ratio limit", ), + is_optional: true, + is_list: false, }, ), Number( TypeInfo { name: "seedingTimeLimit", - is_optional: true, - is_list: false, description: Some( "Set torrent seeding time limit. Unit in seconds", ), + is_optional: true, + is_list: false, }, ), Bool( TypeInfo { name: "autoTMM", - is_optional: true, - is_list: false, description: Some( "Whether Automatic Torrent Management should be used", ), + is_optional: true, + is_list: false, }, ), String( TypeInfo { name: "sequentialDownload", - is_optional: true, - is_list: false, description: Some( "Enable sequential download. Possible values are true, false (default)", ), + is_optional: true, + is_list: false, }, ), String( TypeInfo { name: "firstLastPiecePrio", - is_optional: true, - is_list: false, description: Some( "Prioritize download first last piece. Possible values are true, false (default)", ), + is_optional: true, + is_list: false, }, ), ], + is_list: false, }, ), ], @@ -2388,34 +2427,35 @@ String( TypeInfo { name: "hash", - is_optional: false, - is_list: false, description: Some( "The hash of the torrent", ), + is_optional: false, + is_list: false, }, ), String( TypeInfo { name: "origUrl", - is_optional: false, - is_list: false, description: Some( "The tracker URL you want to edit", ), + is_optional: false, + is_list: false, }, ), String( TypeInfo { name: "newUrl", - is_optional: false, - is_list: false, description: Some( "The new URL to replace the origUrl", ), + is_optional: false, + is_list: false, }, ), ], + is_list: false, }, ), ], @@ -2433,24 +2473,25 @@ String( TypeInfo { name: "hash", - is_optional: false, - is_list: false, description: Some( "The hash of the torrent", ), + is_optional: false, + is_list: false, }, ), String( TypeInfo { name: "urls", - is_optional: false, - is_list: false, description: Some( "URLs to remove, separated by \\", ), + is_optional: false, + is_list: false, }, ), ], + is_list: false, }, ), ], @@ -2468,24 +2509,25 @@ String( TypeInfo { name: "hashes", - is_optional: false, - is_list: false, description: Some( "The hash of the torrent, or multiple hashes separated by a pipe \\", ), + is_optional: false, + is_list: false, }, ), String( TypeInfo { name: "peers", - is_optional: false, - is_list: false, description: Some( "The peer to add, or multiple peers separated by a pipe \\", ), + is_optional: false, + is_list: false, }, ), ], + is_list: false, }, ), ], @@ -2503,14 +2545,15 @@ String( TypeInfo { name: "hashes", - is_optional: false, - is_list: false, description: Some( "The hashes of the torrents you want to increase the priority of. hashes can contain multiple hashes separated by \\", ), + is_optional: false, + is_list: false, }, ), ], + is_list: false, }, ), ], @@ -2528,14 +2571,15 @@ String( TypeInfo { name: "hashes", - is_optional: false, - is_list: false, description: Some( "The hashes of the torrents you want to decrease the priority of. hashes can contain multiple hashes separated by \\", ), + is_optional: false, + is_list: false, }, ), ], + is_list: false, }, ), ], @@ -2553,14 +2597,15 @@ String( TypeInfo { name: "hashes", - is_optional: false, - is_list: false, description: Some( "The hashes of the torrents you want to set to the maximum priority. hashes can contain multiple hashes separated by \\", ), + is_optional: false, + is_list: false, }, ), ], + is_list: false, }, ), ], @@ -2578,14 +2623,15 @@ String( TypeInfo { name: "hashes", - is_optional: false, - is_list: false, description: Some( "The hashes of the torrents you want to set to the minimum priority. hashes can contain multiple hashes separated by \\", ), + is_optional: false, + is_list: false, }, ), ], + is_list: false, }, ), ], @@ -2603,34 +2649,35 @@ String( TypeInfo { name: "hash", - is_optional: false, - is_list: false, description: Some( "The hash of the torrent", ), + is_optional: false, + is_list: false, }, ), String( TypeInfo { name: "id", - is_optional: false, - is_list: false, description: Some( "File ids, separated by \\", ), + is_optional: false, + is_list: false, }, ), Number( TypeInfo { name: "priority", - is_optional: false, - is_list: false, description: Some( "File priority to set (consult [torrent contents API](#get-torrent-contents) for possible values)", ), + is_optional: false, + is_list: false, }, ), ], + is_list: false, }, ), ], @@ -2784,14 +2831,15 @@ String( TypeInfo { name: "hashes", - is_optional: false, - is_list: false, description: Some( "The hashes of the torrents you want to toggle sequential download for. hashes can contain multiple hashes separated by \\", ), + is_optional: false, + is_list: false, }, ), ], + is_list: false, }, ), ], @@ -2809,14 +2857,15 @@ String( TypeInfo { name: "hashes", - is_optional: false, - is_list: false, description: Some( "The hashes of the torrents you want to toggle the first/last piece priority for. hashes can contain multiple hashes separated by \\", ), + is_optional: false, + is_list: false, }, ), ], + is_list: false, }, ), ], @@ -2850,34 +2899,35 @@ String( TypeInfo { name: "hash", - is_optional: false, - is_list: false, description: Some( "The hash of the torrent", ), + is_optional: false, + is_list: false, }, ), String( TypeInfo { name: "oldPath", - is_optional: false, - is_list: false, description: Some( "The old path of the torrent", ), + is_optional: false, + is_list: false, }, ), String( TypeInfo { name: "newPath", - is_optional: false, - is_list: false, description: Some( "The new path to use for the file", ), + is_optional: false, + is_list: false, }, ), ], + is_list: false, }, ), ], @@ -2895,34 +2945,35 @@ String( TypeInfo { name: "hash", - is_optional: false, - is_list: false, description: Some( "The hash of the torrent", ), + is_optional: false, + is_list: false, }, ), String( TypeInfo { name: "oldPath", - is_optional: false, - is_list: false, description: Some( "The old path of the torrent", ), + is_optional: false, + is_list: false, }, ), String( TypeInfo { name: "newPath", - is_optional: false, - is_list: false, description: Some( "The new path to use for the file", ), + is_optional: false, + is_list: false, }, ), ], + is_list: false, }, ), ], @@ -2949,14 +3000,15 @@ String( TypeInfo { name: "path", - is_optional: false, - is_list: false, description: Some( "Full path of added folder (e.g. \"The Pirate Bay\\Top100\")", ), + is_optional: false, + is_list: false, }, ), ], + is_list: false, }, ), ], @@ -2974,24 +3026,25 @@ String( TypeInfo { name: "url", - is_optional: false, - is_list: false, description: Some( "URL of RSS feed (e.g. \"[http://thepiratebay.org/rss//top100/200](http://thepiratebay.org/rss//top100/200)\")", ), + is_optional: false, + is_list: false, }, ), String( TypeInfo { name: "path", - is_optional: true, - is_list: false, description: Some( "Full path of added folder (e.g. \"The Pirate Bay\\Top100\\Video\")", ), + is_optional: true, + is_list: false, }, ), ], + is_list: false, }, ), ], @@ -3009,14 +3062,15 @@ String( TypeInfo { name: "path", - is_optional: false, - is_list: false, description: Some( "Full path of removed item (e.g. \"The Pirate Bay\\Top100\")", ), + is_optional: false, + is_list: false, }, ), ], + is_list: false, }, ), ], @@ -3034,24 +3088,25 @@ String( TypeInfo { name: "itemPath", - is_optional: false, - is_list: false, description: Some( "Current full path of item (e.g. \"The Pirate Bay\\Top100\")", ), + is_optional: false, + is_list: false, }, ), String( TypeInfo { name: "destPath", - is_optional: false, - is_list: false, description: Some( "New full path of item (e.g. \"The Pirate Bay\")", ), + is_optional: false, + is_list: false, }, ), ], + is_list: false, }, ), ], @@ -3069,14 +3124,15 @@ Bool( TypeInfo { name: "withData", - is_optional: true, - is_list: false, description: Some( "True if you need current feed articles", ), + is_optional: true, + is_list: false, }, ), ], + is_list: false, }, ), ], @@ -3094,24 +3150,25 @@ String( TypeInfo { name: "itemPath", - is_optional: false, - is_list: false, description: Some( "Current full path of item (e.g. \"The Pirate Bay\\Top100\")", ), + is_optional: false, + is_list: false, }, ), String( TypeInfo { name: "articleId", - is_optional: true, - is_list: false, description: Some( "ID of article", ), + is_optional: true, + is_list: false, }, ), ], + is_list: false, }, ), ], @@ -3129,14 +3186,15 @@ String( TypeInfo { name: "itemPath", - is_optional: false, - is_list: false, description: Some( "Current full path of item (e.g. \"The Pirate Bay\\Top100\")", ), + is_optional: false, + is_list: false, }, ), ], + is_list: false, }, ), ], @@ -3154,24 +3212,25 @@ String( TypeInfo { name: "ruleName", - is_optional: false, - is_list: false, description: Some( "Rule name (e.g. \"Punisher\")", ), + is_optional: false, + is_list: false, }, ), String( TypeInfo { name: "ruleDef", - is_optional: false, - is_list: false, description: Some( "JSON encoded rule definition", ), + is_optional: false, + is_list: false, }, ), ], + is_list: false, }, ), ], @@ -3189,24 +3248,25 @@ String( TypeInfo { name: "ruleName", - is_optional: false, - is_list: false, description: Some( "Rule name (e.g. \"Punisher\")", ), + is_optional: false, + is_list: false, }, ), String( TypeInfo { name: "newRuleName", - is_optional: false, - is_list: false, description: Some( "New rule name (e.g. \"The Punisher\")", ), + is_optional: false, + is_list: false, }, ), ], + is_list: false, }, ), ], @@ -3224,14 +3284,15 @@ String( TypeInfo { name: "ruleName", - is_optional: false, - is_list: false, description: Some( "Rule name (e.g. \"Punisher\")", ), + is_optional: false, + is_list: false, }, ), ], + is_list: false, }, ), ], @@ -3276,34 +3337,35 @@ String( TypeInfo { name: "pattern", - is_optional: false, - is_list: false, description: Some( "Pattern to search for (e.g. \"Ubuntu 18.04\")", ), + is_optional: false, + is_list: false, }, ), String( TypeInfo { name: "plugins", - is_optional: false, - is_list: false, description: Some( "Plugins to use for searching (e.g. \"legittorrents\"). Supports multiple plugins separated by \\", ), + is_optional: false, + is_list: false, }, ), String( TypeInfo { name: "category", - is_optional: false, - is_list: false, description: Some( "Categories to limit your search to (e.g. \"legittorrents\"). Available categories depend on the specified plugins. Also supports all", ), + is_optional: false, + is_list: false, }, ), ], + is_list: false, }, ), Response( @@ -3312,14 +3374,15 @@ Number( TypeInfo { name: "id", - is_optional: false, - is_list: false, description: Some( "ID of the search job", ), + is_optional: false, + is_list: false, }, ), ], + is_list: false, }, ), ], @@ -3337,14 +3400,15 @@ Number( TypeInfo { name: "id", - is_optional: false, - is_list: false, description: Some( "ID of the search job", ), + is_optional: false, + is_list: false, }, ), ], + is_list: false, }, ), ], @@ -3364,14 +3428,15 @@ Number( TypeInfo { name: "id", - is_optional: true, - is_list: false, description: Some( "ID of the search job. If not specified, all search jobs are returned", ), + is_optional: true, + is_list: false, }, ), ], + is_list: false, }, ), Response( @@ -3380,34 +3445,35 @@ Number( TypeInfo { name: "id", - is_optional: false, - is_list: false, description: Some( "ID of the search job", ), + is_optional: false, + is_list: false, }, ), String( TypeInfo { name: "status", - is_optional: false, - is_list: false, description: Some( "Current status of the search job (either Running or Stopped)", ), + is_optional: false, + is_list: false, }, ), Number( TypeInfo { name: "total", - is_optional: false, - is_list: false, description: Some( "Total number of results. If the status is Running this number may contineu to increase", ), + is_optional: false, + is_list: false, }, ), ], + is_list: true, }, ), ], @@ -3427,34 +3493,35 @@ Number( TypeInfo { name: "id", - is_optional: false, - is_list: false, description: Some( "ID of the search job", ), + is_optional: false, + is_list: false, }, ), Number( TypeInfo { name: "limit", - is_optional: true, - is_list: false, description: Some( "max number of results to return. 0 or negative means no limit", ), + is_optional: true, + is_list: false, }, ), Number( TypeInfo { name: "offset", - is_optional: true, - is_list: false, description: Some( "result to start at. A negative number means count backwards (e.g. -2 returns the 2 most recent results)", ), + is_optional: true, + is_list: false, }, ), ], + is_list: false, }, ), Object( @@ -3464,71 +3531,71 @@ String( TypeInfo { name: "descrLink", - is_optional: false, - is_list: false, description: Some( "URL of the torrent's description page", ), + is_optional: false, + is_list: false, }, ), String( TypeInfo { name: "fileName", - is_optional: false, - is_list: false, description: Some( "Name of the file", ), + is_optional: false, + is_list: false, }, ), Number( TypeInfo { name: "fileSize", - is_optional: false, - is_list: false, description: Some( "Size of the file in Bytes", ), + is_optional: false, + is_list: false, }, ), String( TypeInfo { name: "fileUrl", - is_optional: false, - is_list: false, description: Some( "Torrent download link (usually either .torrent file or magnet link)", ), + is_optional: false, + is_list: false, }, ), Number( TypeInfo { name: "nbLeechers", - is_optional: false, - is_list: false, description: Some( "Number of leechers", ), + is_optional: false, + is_list: false, }, ), Number( TypeInfo { name: "nbSeeders", - is_optional: false, - is_list: false, description: Some( "Number of seeders", ), + is_optional: false, + is_list: false, }, ), String( TypeInfo { name: "siteUrl", - is_optional: false, - is_list: false, description: Some( "URL of the torrent site", ), + is_optional: false, + is_list: false, }, ), ], @@ -3541,36 +3608,37 @@ Object { type_info: TypeInfo { name: "results", - is_optional: false, - is_list: false, description: Some( "Array of result objects- see table below", ), + is_optional: false, + is_list: true, }, - ref_type: "Result", + ref_type: "", }, ), String( TypeInfo { name: "status", - is_optional: false, - is_list: false, description: Some( "Current status of the search job (either Running or Stopped)", ), + is_optional: false, + is_list: false, }, ), Number( TypeInfo { name: "total", - is_optional: false, - is_list: false, description: Some( "Total number of results. If the status is Running this number may continue to increase", ), + is_optional: false, + is_list: false, }, ), ], + is_list: false, }, ), ], @@ -3588,14 +3656,15 @@ Number( TypeInfo { name: "id", - is_optional: false, - is_list: false, description: Some( "ID of the search job", ), + is_optional: false, + is_list: false, }, ), ], + is_list: false, }, ), ], @@ -3615,64 +3684,68 @@ Bool( TypeInfo { name: "enabled", - is_optional: false, - is_list: false, description: Some( "Whether the plugin is enabled", ), + is_optional: false, + is_list: false, }, ), String( TypeInfo { name: "fullName", - is_optional: false, - is_list: false, description: Some( "Full name of the plugin", ), + is_optional: false, + is_list: false, }, ), String( TypeInfo { name: "name", - is_optional: false, - is_list: false, description: Some( "Short name of the plugin", ), - }, - ), - StringArray( - TypeInfo { - name: "supportedCategories", is_optional: false, is_list: false, - description: Some( - "List of category objects", - ), + }, + ), + Object( + Object { + type_info: TypeInfo { + name: "supportedCategories", + description: Some( + "List of category objects", + ), + is_optional: false, + is_list: true, + }, + ref_type: "", }, ), String( TypeInfo { name: "url", - is_optional: false, - is_list: false, description: Some( "URL of the torrent site", ), + is_optional: false, + is_list: false, }, ), String( TypeInfo { name: "version", - is_optional: false, - is_list: false, description: Some( "Installed version of the plugin", ), + is_optional: false, + is_list: false, }, ), ], + is_list: true, }, ), ], @@ -3690,14 +3763,15 @@ String( TypeInfo { name: "sources", - is_optional: false, - is_list: false, description: Some( "Url or file path of the plugin to install (e.g. \"[https://raw.githubusercontent.com/qbittorrent/search-plugins/master/nova3/engines/legittorrents.py](https://raw.githubusercontent.com/qbittorrent/search-plugins/master/nova3/engines/legittorrents.py)\"). Supports multiple sources separated by \\", ), + is_optional: false, + is_list: false, }, ), ], + is_list: false, }, ), ], @@ -3715,14 +3789,15 @@ String( TypeInfo { name: "names", - is_optional: false, - is_list: false, description: Some( "Name of the plugin to uninstall (e.g. \"legittorrents\"). Supports multiple names separated by \\", ), + is_optional: false, + is_list: false, }, ), ], + is_list: false, }, ), ], @@ -3740,24 +3815,25 @@ String( TypeInfo { name: "names", - is_optional: false, - is_list: false, description: Some( "Name of the plugin to enable/disable (e.g. \"legittorrents\"). Supports multiple names separated by \\", ), + is_optional: false, + is_list: false, }, ), Bool( TypeInfo { name: "enable", - is_optional: false, - is_list: false, description: Some( "Whether the plugins should be enabled", ), + is_optional: false, + is_list: false, }, ), ], + is_list: false, }, ), ], diff --git a/qbittorrent-web-api-gen/src/generate/group/mod.rs b/qbittorrent-web-api-gen/src/generate/group/mod.rs index 454c165..7003673 100644 --- a/qbittorrent-web-api-gen/src/generate/group/mod.rs +++ b/qbittorrent-web-api-gen/src/generate/group/mod.rs @@ -150,13 +150,18 @@ impl types::Type { fn generate_struct_field(&self) -> TokenStream { let name_snake = self.name_snake(); let type_name = util::to_ident(&self.to_owned_type()); + let type_ = if self.is_list() { + quote! { std::vec::Vec<#type_name> } + } else { + quote! { #type_name } + }; let orig_name = self.name(); util::add_docs( &self.get_type_info().description, quote! { #[serde(rename = #orig_name)] - pub #name_snake: #type_name + pub #name_snake: #type_ }, ) } @@ -292,7 +297,10 @@ impl<'a> GroupMethod<'a> { None => return quote! {}, }; - let struct_fields = response.iter().map(|field| field.generate_struct_field()); + let struct_fields = response + .types + .iter() + .map(|field| field.generate_struct_field()); quote! { #[derive(Debug, serde::Deserialize)] @@ -347,7 +355,16 @@ impl<'a> GroupMethod<'a> { let method_url = format!("/api/v2/{}/{}", self.group.url, self.method.url); let (response_type, response_parse) = match self.method.types.response() { - Some(_) => (quote! { Response }, quote! { .json::() }), + Some(resp) => { + if resp.is_list { + ( + quote! { std::vec::Vec }, + quote! { .json::>() }, + ) + } else { + (quote! { Response }, quote! { .json::() }) + } + } None => (quote! { String }, quote! { .text() }), }; diff --git a/qbittorrent-web-api-gen/src/parser/group/method/method_tests/array_field.check b/qbittorrent-web-api-gen/src/parser/group/method/method_tests/array_field.check new file mode 100644 index 0000000..cb6792d --- /dev/null +++ b/qbittorrent-web-api-gen/src/parser/group/method/method_tests/array_field.check @@ -0,0 +1,26 @@ +ApiMethod { + name: "foo", + description: None, + url: "foo", + types: CompositeTypes { + composite_types: [ + Response( + TypeWithoutName { + types: [ + Number( + TypeInfo { + name: "amount_left", + description: Some( + "Amount of data left to download (bytes)", + ), + is_optional: false, + is_list: true, + }, + ), + ], + is_list: false, + }, + ), + ], + }, +} \ No newline at end of file diff --git a/qbittorrent-web-api-gen/src/parser/group/method/method_tests/array_field.md b/qbittorrent-web-api-gen/src/parser/group/method/method_tests/array_field.md new file mode 100644 index 0000000..dc34aa3 --- /dev/null +++ b/qbittorrent-web-api-gen/src/parser/group/method/method_tests/array_field.md @@ -0,0 +1,9 @@ +## Testing + +Name: `foo` + +The response is a JSON object with the following fields + +Property | Type | Description +---------------------|---------|------------ +`amount_left` | integer array | Amount of data left to download (bytes) diff --git a/qbittorrent-web-api-gen/src/parser/group/method/method_tests/array_field.tree b/qbittorrent-web-api-gen/src/parser/group/method/method_tests/array_field.tree new file mode 100644 index 0000000..687e642 --- /dev/null +++ b/qbittorrent-web-api-gen/src/parser/group/method/method_tests/array_field.tree @@ -0,0 +1,52 @@ +TokenTree { + title: None, + content: [], + children: [ + TokenTree { + title: Some( + "Testing", + ), + content: [ + Text( + "", + ), + Text( + "Name: `foo`", + ), + Text( + "", + ), + Text( + "The response is a JSON object with the following fields", + ), + Text( + "", + ), + Table( + Table { + header: TableRow { + raw: "Property | Type | Description", + columns: [ + "Property", + "Type", + "Description", + ], + }, + split: "---------------------|---------|------------", + rows: [ + TableRow { + raw: "`amount_left` | integer array | Amount of data left to download (bytes)", + columns: [ + "amount_left", + "integer array", + "Amount of data left to download (bytes)", + ], + }, + ], + }, + ), + ], + children: [], + }, + ], +} \ No newline at end of file diff --git a/qbittorrent-web-api-gen/src/parser/group/method/method_tests/array_result.check b/qbittorrent-web-api-gen/src/parser/group/method/method_tests/array_result.check new file mode 100644 index 0000000..674cd63 --- /dev/null +++ b/qbittorrent-web-api-gen/src/parser/group/method/method_tests/array_result.check @@ -0,0 +1,26 @@ +ApiMethod { + name: "foo", + description: None, + url: "foo", + types: CompositeTypes { + composite_types: [ + Response( + TypeWithoutName { + types: [ + Number( + TypeInfo { + name: "added_on", + description: Some( + "Time (Unix Epoch) when the torrent was added to the client", + ), + is_optional: false, + is_list: false, + }, + ), + ], + is_list: true, + }, + ), + ], + }, +} \ No newline at end of file diff --git a/qbittorrent-web-api-gen/src/parser/group/method/method_tests/array_result.md b/qbittorrent-web-api-gen/src/parser/group/method/method_tests/array_result.md new file mode 100644 index 0000000..3e8a748 --- /dev/null +++ b/qbittorrent-web-api-gen/src/parser/group/method/method_tests/array_result.md @@ -0,0 +1,9 @@ +## Testing + +Name: `foo` + +The response is a JSON array with the following fields + +Property | Type | Description +---------------------|---------|------------ +`added_on` | integer | Time (Unix Epoch) when the torrent was added to the client diff --git a/qbittorrent-web-api-gen/src/parser/group/method/method_tests/array_result.tree b/qbittorrent-web-api-gen/src/parser/group/method/method_tests/array_result.tree new file mode 100644 index 0000000..7589f7a --- /dev/null +++ b/qbittorrent-web-api-gen/src/parser/group/method/method_tests/array_result.tree @@ -0,0 +1,52 @@ +TokenTree { + title: None, + content: [], + children: [ + TokenTree { + title: Some( + "Testing", + ), + content: [ + Text( + "", + ), + Text( + "Name: `foo`", + ), + Text( + "", + ), + Text( + "The response is a JSON array with the following fields", + ), + Text( + "", + ), + Table( + Table { + header: TableRow { + raw: "Property | Type | Description", + columns: [ + "Property", + "Type", + "Description", + ], + }, + split: "---------------------|---------|------------", + rows: [ + TableRow { + raw: "`added_on` | integer | Time (Unix Epoch) when the torrent was added to the client", + columns: [ + "added_on", + "integer", + "Time (Unix Epoch) when the torrent was added to the client", + ], + }, + ], + }, + ), + ], + children: [], + }, + ], +} \ No newline at end of file diff --git a/qbittorrent-web-api-gen/src/parser/group/method/method_tests/search_result.check b/qbittorrent-web-api-gen/src/parser/group/method/method_tests/search_result.check index 48fccea..44fc18c 100644 --- a/qbittorrent-web-api-gen/src/parser/group/method/method_tests/search_result.check +++ b/qbittorrent-web-api-gen/src/parser/group/method/method_tests/search_result.check @@ -12,34 +12,35 @@ ApiMethod { Number( TypeInfo { name: "id", - is_optional: false, - is_list: false, description: Some( "ID of the search job", ), + is_optional: false, + is_list: false, }, ), Number( TypeInfo { name: "limit", - is_optional: true, - is_list: false, description: Some( "max number of results to return. 0 or negative means no limit", ), + is_optional: true, + is_list: false, }, ), Number( TypeInfo { name: "offset", - is_optional: true, - is_list: false, description: Some( "result to start at. A negative number means count backwards (e.g. -2 returns the 2 most recent results)", ), + is_optional: true, + is_list: false, }, ), ], + is_list: false, }, ), Object( @@ -49,71 +50,71 @@ ApiMethod { String( TypeInfo { name: "descrLink", - is_optional: false, - is_list: false, description: Some( "URL of the torrent's description page", ), + is_optional: false, + is_list: false, }, ), String( TypeInfo { name: "fileName", - is_optional: false, - is_list: false, description: Some( "Name of the file", ), + is_optional: false, + is_list: false, }, ), Number( TypeInfo { name: "fileSize", - is_optional: false, - is_list: false, description: Some( "Size of the file in Bytes", ), + is_optional: false, + is_list: false, }, ), String( TypeInfo { name: "fileUrl", - is_optional: false, - is_list: false, description: Some( "Torrent download link (usually either .torrent file or magnet link)", ), + is_optional: false, + is_list: false, }, ), Number( TypeInfo { name: "nbLeechers", - is_optional: false, - is_list: false, description: Some( "Number of leechers", ), + is_optional: false, + is_list: false, }, ), Number( TypeInfo { name: "nbSeeders", - is_optional: false, - is_list: false, description: Some( "Number of seeders", ), + is_optional: false, + is_list: false, }, ), String( TypeInfo { name: "siteUrl", - is_optional: false, - is_list: false, description: Some( "URL of the torrent site", ), + is_optional: false, + is_list: false, }, ), ], @@ -126,36 +127,37 @@ ApiMethod { Object { type_info: TypeInfo { name: "results", - is_optional: false, - is_list: false, description: Some( "Array of result objects- see table below", ), + is_optional: false, + is_list: true, }, - ref_type: "Result", + ref_type: "", }, ), String( TypeInfo { name: "status", - is_optional: false, - is_list: false, description: Some( "Current status of the search job (either Running or Stopped)", ), + is_optional: false, + is_list: false, }, ), Number( TypeInfo { name: "total", - is_optional: false, - is_list: false, description: Some( "Total number of results. If the status is Running this number may continue to increase", ), + is_optional: false, + is_list: false, }, ), ], + is_list: false, }, ), ], diff --git a/qbittorrent-web-api-gen/src/parser/group/method/mod.rs b/qbittorrent-web-api-gen/src/parser/group/method/mod.rs index 4a50f62..6788151 100644 --- a/qbittorrent-web-api-gen/src/parser/group/method/mod.rs +++ b/qbittorrent-web-api-gen/src/parser/group/method/mod.rs @@ -53,9 +53,9 @@ impl CompositeTypes { .collect() } - pub fn response(&self) -> Option<&Vec> { + pub fn response(&self) -> Option<&TypeWithoutName> { self.composite_types.iter().find_map(|type_| match type_ { - CompositeType::Response(p) => Some(&p.types), + CompositeType::Response(p) => Some(p), _ => None, }) } @@ -104,11 +104,12 @@ pub struct TypeWithName { #[derive(Debug)] pub struct TypeWithoutName { pub types: Vec, + pub is_list: bool, } impl TypeWithoutName { - pub fn new(types: Vec) -> Self { - Self { types } + pub fn new(types: Vec, is_list: bool) -> Self { + Self { types, is_list } } } @@ -270,6 +271,7 @@ impl md_parser::Table { Some(CompositeType::Response(TypeWithoutName::new( self.to_types(), + input_name.to_lowercase().contains("array"), ))) } @@ -280,6 +282,7 @@ impl md_parser::Table { Some(CompositeType::Parameters(TypeWithoutName::new( self.to_types(), + input_name.to_lowercase().contains("array"), ))) } @@ -409,4 +412,14 @@ mod tests { fn enum_test() { run_test!("enum"); } + + #[test] + fn array_result() { + run_test!("array_result"); + } + + #[test] + fn array_field() { + run_test!("array_field"); + } } diff --git a/qbittorrent-web-api-gen/src/types.rs b/qbittorrent-web-api-gen/src/types.rs index 498498c..565dcc1 100644 --- a/qbittorrent-web-api-gen/src/types.rs +++ b/qbittorrent-web-api-gen/src/types.rs @@ -15,18 +15,18 @@ pub struct TypeDescription { #[derive(Debug, Clone)] pub struct TypeInfo { pub name: String, - pub is_optional: bool, - pub is_list: bool, pub description: Option, + is_optional: bool, + is_list: bool, } impl TypeInfo { pub fn new(name: &str, is_optional: bool, is_list: bool, description: Option) -> Self { Self { name: name.into(), + description, is_optional, is_list, - description, } } } @@ -93,6 +93,10 @@ impl Type { self.get_type_info().is_optional } + pub fn is_list(&self) -> bool { + self.get_type_info().is_list + } + pub fn get_type_info(&self) -> &TypeInfo { match self { Type::Number(t) => t, @@ -116,8 +120,21 @@ impl Type { .clone() .map(|desc| desc.contains("array")) .unwrap_or(false); - let create_type_info = - || TypeInfo::new(type_name, is_optional, is_list, description.clone()); + + let (type_without_array, type_contains_array) = if type_as_str.contains("array") { + (type_as_str.replace("array", ""), true) + } else { + (type_as_str.to_owned(), false) + }; + + let create_type_info = || { + TypeInfo::new( + type_name, + is_optional, + is_list || type_contains_array, + description.clone(), + ) + }; let create_object_type = |name: &str| { Some(Type::Object(Object { @@ -126,7 +143,7 @@ impl Type { })) }; - match type_as_str { + match type_without_array.trim() { "raw" => None, "bool" => Some(Type::Bool(create_type_info())), "integer" | "number" | "int" => Some(Type::Number(create_type_info())), diff --git a/qbittorrent-web-api-gen/tests/access_impl_types.rs b/qbittorrent-web-api-gen/tests/access_impl_types.rs index cc59017..b0f6148 100644 --- a/qbittorrent-web-api-gen/tests/access_impl_types.rs +++ b/qbittorrent-web-api-gen/tests/access_impl_types.rs @@ -10,7 +10,7 @@ mod foo { #[tokio::main] async fn main() -> Result<()> { - let _ = foo::api_impl::ApplicationPreferencesBittorrentProtocol::TCP; + let _ = foo::api_impl::application::preferences::BittorrentProtocol::TCP; Ok(()) } From dcacdcda9c23e0b5cb51d931e1d36406761405c3 Mon Sep 17 00:00:00 2001 From: Joel Wachsler Date: Sat, 23 Jul 2022 00:23:17 +0000 Subject: [PATCH 43/47] Fix response tests --- qbittorrent-web-api-gen/api-4_1.md | 99 ++- qbittorrent-web-api-gen/groups.txt | 655 +++++++++++++++++- .../src/generate/group/mod.rs | 37 +- .../group/method/method_tests/ref_type.check | 110 +++ .../group/method/method_tests/ref_type.md | 65 ++ .../group/method/method_tests/ref_type.tree | 276 ++++++++ .../method/method_tests/search_result.check | 4 +- .../src/parser/group/method/mod.rs | 5 + qbittorrent-web-api-gen/src/types.rs | 106 ++- qbittorrent-web-api-gen/token_tree.txt | 583 +++++++++++++++- 10 files changed, 1839 insertions(+), 101 deletions(-) create mode 100644 qbittorrent-web-api-gen/src/parser/group/method/method_tests/ref_type.check create mode 100644 qbittorrent-web-api-gen/src/parser/group/method/method_tests/ref_type.md create mode 100644 qbittorrent-web-api-gen/src/parser/group/method/method_tests/ref_type.tree diff --git a/qbittorrent-web-api-gen/api-4_1.md b/qbittorrent-web-api-gen/api-4_1.md index cf94502..35e55f5 100644 --- a/qbittorrent-web-api-gen/api-4_1.md +++ b/qbittorrent-web-api-gen/api-4_1.md @@ -1002,17 +1002,17 @@ HTTP Status Code | Scenario The response is a JSON object with the following possible fields -Property | Type | Description -------------------------------|---------|------------ -`rid` | integer | Response ID -`full_update` | bool | Whether the response contains all the data or partial data -`torrents` | object | Property: torrent hash, value: same as [torrent list](#get-torrent-list) -`torrents_removed` | array | List of hashes of torrents removed since last request -`categories` | object | Info for categories added since last request -`categories_removed` | array | List of categories removed since last request -`tags` | array | List of tags added since last request -`tags_removed` | array | List of tags removed since last request -`server_state` | object | Global transfer info +Property | Type | Description +--------------------------------|-----------|------------ +`rid` | integer | Response ID +`full_update`_optional_ | bool | Whether the response contains all the data or partial data +`torrents`_optional_ | object | Property: torrent hash, value: same as [torrent list](#get-torrent-list), map from string to torrents object +`torrents_removed`_optional_ | array | List of hashes of torrents removed since last request +`categories`_optional_ | object | Info for categories added since last request, map from string to categories object +`categories_removed`_optional_ | array | List of categories removed since last request +`tags`_optional_ | array | List of tags added since last request +`tags_removed`_optional_ | array | List of tags removed since last request +`server_state`_optional_ | object | `server_state` object see table below Example: @@ -1029,6 +1029,74 @@ Example: } ``` +**ServerState object:** + +Property | Type | Description +------------------------------|---------|------------ +`average_time_queue` | integer | Average time queue +`dl_info_data` | number | Download info data +`dl_info_speed` | number | Download info speed +`queued_io_jobs` | integer | Queued io jobs +`total_buffers_size` | number | Total buffers size +`total_peer_connections` | integer | Total peer connections + +**Categories object:** + +Property | Type | Description +------------------------------|---------|------------ +`name` | string | Category name +`savePath` | string | Save path + +**Torrents object:** + +Property | Type | Description +--------------------------------|-----------|------------ +`added_on`_optional_ | integer | Time (Unix Epoch) when the torrent was added to the client +`amount_left`_optional_ | integer | Amount of data left to download (bytes) +`auto_tmm`_optional_ | bool | Whether this torrent is managed by Automatic Torrent Management +`availability`_optional_ | float | Percentage of file pieces currently available +`category`_optional_ | string | Category of the torrent +`completed`_optional_ | integer | Amount of transfer data completed (bytes) +`completion_on`_optional_ | integer | Time (Unix Epoch) when the torrent completed +`content_path`_optional_ | string | Absolute path of torrent content (root path for multifile torrents, absolute file path for singlefile torrents) +`dl_limit`_optional_ | integer | Torrent download speed limit (bytes/s). `-1` if ulimited. +`dlspeed`_optional_ | integer | Torrent download speed (bytes/s) +`downloaded`_optional_ | integer | Amount of data downloaded +`downloaded_session`_optional_ | integer | Amount of data downloaded this session +`eta`_optional_ | integer | Torrent ETA (seconds) +`f_l_piece_prio`_optional_ | bool | True if first last piece are prioritized +`force_start`_optional_ | bool | True if force start is enabled for this torrent +`hash`_optional_ | string | Torrent hash +`last_activity`_optional_ | integer | Last time (Unix Epoch) when a chunk was downloaded/uploaded +`magnet_uri`_optional_ | string | Magnet URI corresponding to this torrent +`max_ratio`_optional_ | float | Maximum share ratio until torrent is stopped from seeding/uploading +`max_seeding_time`_optional_ | integer | Maximum seeding time (seconds) until torrent is stopped from seeding +`name`_optional_ | string | Torrent name +`num_complete`_optional_ | integer | Number of seeds in the swarm +`num_incomplete`_optional_ | integer | Number of leechers in the swarm +`num_leechs`_optional_ | integer | Number of leechers connected to +`num_seeds`_optional_ | integer | Number of seeds connected to +`priority`_optional_ | integer | Torrent priority. Returns -1 if queuing is disabled or torrent is in seed mode +`progress`_optional_ | float | Torrent progress (percentage/100) +`ratio`_optional_ | float | Torrent share ratio. Max ratio value: 9999. +`ratio_limit`_optional_ | float | TODO (what is different from `max_ratio`?) +`save_path`_optional_ | string | Path where this torrent's data is stored +`seeding_time`_optional_ | integer | Torrent elapsed time while complete (seconds) +`seeding_time_limit`_optional_ | integer | TODO (what is different from `max_seeding_time`?) seeding_time_limit is a per torrent setting, when Automatic Torrent Management is disabled, furthermore then max_seeding_time is set to seeding_time_limit for this torrent. If Automatic Torrent Management is enabled, the value is -2. And if max_seeding_time is unset it have a default value -1. +`seen_complete`_optional_ | integer | Time (Unix Epoch) when this torrent was last seen complete +`seq_dl`_optional_ | bool | True if sequential download is enabled +`size`_optional_ | integer | Total size (bytes) of files selected for download +`state`_optional_ | string | Torrent state. See table here below for the possible values +`super_seeding`_optional_ | bool | True if super seeding is enabled +`tags`_optional_ | string | Comma-concatenated tag list of the torrent +`time_active`_optional_ | integer | Total active time (seconds) +`total_size`_optional_ | integer | Total size (bytes) of all file in this torrent (including unselected ones) +`tracker`_optional_ | string | The first tracker with working status. Returns empty string if no tracker is working. +`up_limit`_optional_ | integer | Torrent upload speed limit (bytes/s). `-1` if ulimited. +`uploaded`_optional_ | integer | Amount of data uploaded +`uploaded_session`_optional_ | integer | Amount of data uploaded this session +`upspeed`_optional_ | integer | Torrent upload speed (bytes/s) + ## Get torrent peers data ## Name: `torrentPeers` @@ -1756,7 +1824,7 @@ Name: `delete` Parameter | Type | Description ------------|----------|------------ `hashes` | string | The hashes of the torrents you want to delete. `hashes` can contain multiple hashes separated by `\|`, to delete multiple torrents, or set to `all`, to delete all torrents. -`deleteFiles` | If set to `true`, the downloaded data will also be deleted, otherwise has no effect. +`deleteFiles` | bool | If set to `true`, the downloaded data will also be deleted, otherwise has no effect. Example: @@ -3275,6 +3343,13 @@ Field | Type | Description ] ``` +**Category object:** + +Field | Type | Description +---------------------------|---------|------------ +`id` | string | Id +`name` | string | Name + ## Install search plugin ## Name: `installPlugin` diff --git a/qbittorrent-web-api-gen/groups.txt b/qbittorrent-web-api-gen/groups.txt index 0cf22a1..e470003 100644 --- a/qbittorrent-web-api-gen/groups.txt +++ b/qbittorrent-web-api-gen/groups.txt @@ -628,6 +628,33 @@ url: "maindata", types: CompositeTypes { composite_types: [ + Object( + TypeWithName { + name: "Categories", + types: [ + String( + TypeInfo { + name: "name", + description: Some( + "Category name", + ), + is_optional: false, + is_list: false, + }, + ), + String( + TypeInfo { + name: "savePath", + description: Some( + "Save path", + ), + is_optional: false, + is_list: false, + }, + ), + ], + }, + ), Parameters( TypeWithoutName { types: [ @@ -645,6 +672,73 @@ is_list: false, }, ), + Object( + TypeWithName { + name: "ServerState", + types: [ + Number( + TypeInfo { + name: "average_time_queue", + description: Some( + "Average time queue", + ), + is_optional: false, + is_list: false, + }, + ), + Number( + TypeInfo { + name: "dl_info_data", + description: Some( + "Download info data", + ), + is_optional: false, + is_list: false, + }, + ), + Number( + TypeInfo { + name: "dl_info_speed", + description: Some( + "Download info speed", + ), + is_optional: false, + is_list: false, + }, + ), + Number( + TypeInfo { + name: "queued_io_jobs", + description: Some( + "Queued io jobs", + ), + is_optional: false, + is_list: false, + }, + ), + Number( + TypeInfo { + name: "total_buffers_size", + description: Some( + "Total buffers size", + ), + is_optional: false, + is_list: false, + }, + ), + Number( + TypeInfo { + name: "total_peer_connections", + description: Some( + "Total peer connections", + ), + is_optional: false, + is_list: false, + }, + ), + ], + }, + ), Response( TypeWithoutName { types: [ @@ -664,7 +758,7 @@ description: Some( "Whether the response contains all the data or partial data", ), - is_optional: false, + is_optional: true, is_list: false, }, ), @@ -673,12 +767,15 @@ type_info: TypeInfo { name: "torrents", description: Some( - "Property: torrent hash, value: same as [torrent list](#get-torrent-list)", + "Property: torrent hash, value: same as [torrent list](#get-torrent-list), map from string to torrents object", ), - is_optional: false, + is_optional: true, is_list: false, }, - ref_type: "Object", + ref_type: Map( + "String", + "Torrents", + ), }, ), Object( @@ -688,10 +785,12 @@ description: Some( "List of hashes of torrents removed since last request", ), - is_optional: false, + is_optional: true, is_list: true, }, - ref_type: "", + ref_type: String( + "String", + ), }, ), Object( @@ -699,12 +798,15 @@ type_info: TypeInfo { name: "categories", description: Some( - "Info for categories added since last request", + "Info for categories added since last request, map from string to categories object", ), - is_optional: false, + is_optional: true, is_list: false, }, - ref_type: "Object", + ref_type: Map( + "String", + "Categories", + ), }, ), Object( @@ -714,10 +816,12 @@ description: Some( "List of categories removed since last request", ), - is_optional: false, + is_optional: true, is_list: true, }, - ref_type: "", + ref_type: String( + "String", + ), }, ), Object( @@ -727,10 +831,12 @@ description: Some( "List of tags added since last request", ), - is_optional: false, + is_optional: true, is_list: true, }, - ref_type: "", + ref_type: String( + "String", + ), }, ), Object( @@ -740,10 +846,12 @@ description: Some( "List of tags removed since last request", ), - is_optional: false, + is_optional: true, is_list: true, }, - ref_type: "", + ref_type: String( + "String", + ), }, ), Object( @@ -751,18 +859,477 @@ type_info: TypeInfo { name: "server_state", description: Some( - "Global transfer info", + "server_state object see table below", ), - is_optional: false, + is_optional: true, is_list: false, }, - ref_type: "Object", + ref_type: String( + "ServerState", + ), }, ), ], is_list: false, }, ), + Object( + TypeWithName { + name: "Torrents", + types: [ + Number( + TypeInfo { + name: "added_on", + description: Some( + "Time (Unix Epoch) when the torrent was added to the client", + ), + is_optional: true, + is_list: false, + }, + ), + Number( + TypeInfo { + name: "amount_left", + description: Some( + "Amount of data left to download (bytes)", + ), + is_optional: true, + is_list: false, + }, + ), + Bool( + TypeInfo { + name: "auto_tmm", + description: Some( + "Whether this torrent is managed by Automatic Torrent Management", + ), + is_optional: true, + is_list: false, + }, + ), + Float( + TypeInfo { + name: "availability", + description: Some( + "Percentage of file pieces currently available", + ), + is_optional: true, + is_list: false, + }, + ), + String( + TypeInfo { + name: "category", + description: Some( + "Category of the torrent", + ), + is_optional: true, + is_list: false, + }, + ), + Number( + TypeInfo { + name: "completed", + description: Some( + "Amount of transfer data completed (bytes)", + ), + is_optional: true, + is_list: false, + }, + ), + Number( + TypeInfo { + name: "completion_on", + description: Some( + "Time (Unix Epoch) when the torrent completed", + ), + is_optional: true, + is_list: false, + }, + ), + String( + TypeInfo { + name: "content_path", + description: Some( + "Absolute path of torrent content (root path for multifile torrents, absolute file path for singlefile torrents)", + ), + is_optional: true, + is_list: false, + }, + ), + Number( + TypeInfo { + name: "dl_limit", + description: Some( + "Torrent download speed limit (bytes/s). -1 if ulimited.", + ), + is_optional: true, + is_list: false, + }, + ), + Number( + TypeInfo { + name: "dlspeed", + description: Some( + "Torrent download speed (bytes/s)", + ), + is_optional: true, + is_list: false, + }, + ), + Number( + TypeInfo { + name: "downloaded", + description: Some( + "Amount of data downloaded", + ), + is_optional: true, + is_list: false, + }, + ), + Number( + TypeInfo { + name: "downloaded_session", + description: Some( + "Amount of data downloaded this session", + ), + is_optional: true, + is_list: false, + }, + ), + Number( + TypeInfo { + name: "eta", + description: Some( + "Torrent ETA (seconds)", + ), + is_optional: true, + is_list: false, + }, + ), + Bool( + TypeInfo { + name: "f_l_piece_prio", + description: Some( + "True if first last piece are prioritized", + ), + is_optional: true, + is_list: false, + }, + ), + Bool( + TypeInfo { + name: "force_start", + description: Some( + "True if force start is enabled for this torrent", + ), + is_optional: true, + is_list: false, + }, + ), + String( + TypeInfo { + name: "hash", + description: Some( + "Torrent hash", + ), + is_optional: true, + is_list: false, + }, + ), + Number( + TypeInfo { + name: "last_activity", + description: Some( + "Last time (Unix Epoch) when a chunk was downloaded/uploaded", + ), + is_optional: true, + is_list: false, + }, + ), + String( + TypeInfo { + name: "magnet_uri", + description: Some( + "Magnet URI corresponding to this torrent", + ), + is_optional: true, + is_list: false, + }, + ), + Float( + TypeInfo { + name: "max_ratio", + description: Some( + "Maximum share ratio until torrent is stopped from seeding/uploading", + ), + is_optional: true, + is_list: false, + }, + ), + Number( + TypeInfo { + name: "max_seeding_time", + description: Some( + "Maximum seeding time (seconds) until torrent is stopped from seeding", + ), + is_optional: true, + is_list: false, + }, + ), + String( + TypeInfo { + name: "name", + description: Some( + "Torrent name", + ), + is_optional: true, + is_list: false, + }, + ), + Number( + TypeInfo { + name: "num_complete", + description: Some( + "Number of seeds in the swarm", + ), + is_optional: true, + is_list: false, + }, + ), + Number( + TypeInfo { + name: "num_incomplete", + description: Some( + "Number of leechers in the swarm", + ), + is_optional: true, + is_list: false, + }, + ), + Number( + TypeInfo { + name: "num_leechs", + description: Some( + "Number of leechers connected to", + ), + is_optional: true, + is_list: false, + }, + ), + Number( + TypeInfo { + name: "num_seeds", + description: Some( + "Number of seeds connected to", + ), + is_optional: true, + is_list: false, + }, + ), + Number( + TypeInfo { + name: "priority", + description: Some( + "Torrent priority. Returns -1 if queuing is disabled or torrent is in seed mode", + ), + is_optional: true, + is_list: false, + }, + ), + Float( + TypeInfo { + name: "progress", + description: Some( + "Torrent progress (percentage/100)", + ), + is_optional: true, + is_list: false, + }, + ), + Float( + TypeInfo { + name: "ratio", + description: Some( + "Torrent share ratio. Max ratio value: 9999.", + ), + is_optional: true, + is_list: false, + }, + ), + Float( + TypeInfo { + name: "ratio_limit", + description: Some( + "TODO (what is different from max_ratio?)", + ), + is_optional: true, + is_list: false, + }, + ), + String( + TypeInfo { + name: "save_path", + description: Some( + "Path where this torrent's data is stored", + ), + is_optional: true, + is_list: false, + }, + ), + Number( + TypeInfo { + name: "seeding_time", + description: Some( + "Torrent elapsed time while complete (seconds)", + ), + is_optional: true, + is_list: false, + }, + ), + Number( + TypeInfo { + name: "seeding_time_limit", + description: Some( + "TODO (what is different from max_seeding_time?) seeding_time_limit is a per torrent setting, when Automatic Torrent Management is disabled, furthermore then max_seeding_time is set to seeding_time_limit for this torrent. If Automatic Torrent Management is enabled, the value is -2. And if max_seeding_time is unset it have a default value -1.", + ), + is_optional: true, + is_list: false, + }, + ), + Number( + TypeInfo { + name: "seen_complete", + description: Some( + "Time (Unix Epoch) when this torrent was last seen complete", + ), + is_optional: true, + is_list: false, + }, + ), + Bool( + TypeInfo { + name: "seq_dl", + description: Some( + "True if sequential download is enabled", + ), + is_optional: true, + is_list: false, + }, + ), + Number( + TypeInfo { + name: "size", + description: Some( + "Total size (bytes) of files selected for download", + ), + is_optional: true, + is_list: false, + }, + ), + String( + TypeInfo { + name: "state", + description: Some( + "Torrent state. See table here below for the possible values", + ), + is_optional: true, + is_list: false, + }, + ), + Bool( + TypeInfo { + name: "super_seeding", + description: Some( + "True if super seeding is enabled", + ), + is_optional: true, + is_list: false, + }, + ), + String( + TypeInfo { + name: "tags", + description: Some( + "Comma-concatenated tag list of the torrent", + ), + is_optional: true, + is_list: false, + }, + ), + Number( + TypeInfo { + name: "time_active", + description: Some( + "Total active time (seconds)", + ), + is_optional: true, + is_list: false, + }, + ), + Number( + TypeInfo { + name: "total_size", + description: Some( + "Total size (bytes) of all file in this torrent (including unselected ones)", + ), + is_optional: true, + is_list: false, + }, + ), + String( + TypeInfo { + name: "tracker", + description: Some( + "The first tracker with working status. Returns empty string if no tracker is working.", + ), + is_optional: true, + is_list: false, + }, + ), + Number( + TypeInfo { + name: "up_limit", + description: Some( + "Torrent upload speed limit (bytes/s). -1 if ulimited.", + ), + is_optional: true, + is_list: false, + }, + ), + Number( + TypeInfo { + name: "uploaded", + description: Some( + "Amount of data uploaded", + ), + is_optional: true, + is_list: false, + }, + ), + Number( + TypeInfo { + name: "uploaded_session", + description: Some( + "Amount of data uploaded this session", + ), + is_optional: true, + is_list: false, + }, + ), + Number( + TypeInfo { + name: "upspeed", + description: Some( + "Torrent upload speed (bytes/s)", + ), + is_optional: true, + is_list: false, + }, + ), + ], + }, + ), ], }, }, @@ -2161,15 +2728,14 @@ is_list: false, }, ), - Object( - Object { - type_info: TypeInfo { - name: "deleteFiles", - description: None, - is_optional: false, - is_list: false, - }, - ref_type: "If set to true, the downloaded data will also be deleted, otherwise has no effect.", + Bool( + TypeInfo { + name: "deleteFiles", + description: Some( + "If set to true, the downloaded data will also be deleted, otherwise has no effect.", + ), + is_optional: false, + is_list: false, }, ), ], @@ -3614,7 +4180,9 @@ is_optional: false, is_list: true, }, - ref_type: "", + ref_type: String( + "Result", + ), }, ), String( @@ -3678,6 +4246,33 @@ url: "plugins", types: CompositeTypes { composite_types: [ + Object( + TypeWithName { + name: "Category", + types: [ + String( + TypeInfo { + name: "id", + description: Some( + "Id", + ), + is_optional: false, + is_list: false, + }, + ), + String( + TypeInfo { + name: "name", + description: Some( + "Name", + ), + is_optional: false, + is_list: false, + }, + ), + ], + }, + ), Response( TypeWithoutName { types: [ @@ -3721,7 +4316,9 @@ is_optional: false, is_list: true, }, - ref_type: "", + ref_type: String( + "Category", + ), }, ), String( diff --git a/qbittorrent-web-api-gen/src/generate/group/mod.rs b/qbittorrent-web-api-gen/src/generate/group/mod.rs index 7003673..111b0fc 100644 --- a/qbittorrent-web-api-gen/src/generate/group/mod.rs +++ b/qbittorrent-web-api-gen/src/generate/group/mod.rs @@ -147,14 +147,36 @@ impl parser::TypeWithName { } impl types::Type { + fn owned_type_ident(&self) -> TokenStream { + let owned_type = match self { + types::Type::Number(_) => quote! { i128 }, + types::Type::Float(_) => quote! { f32 }, + types::Type::Bool(_) => quote! { bool }, + types::Type::String(_) => quote! { String }, + types::Type::StringArray(_) => quote! { String }, + types::Type::Object(obj) => match &obj.ref_type { + types::RefType::String(str) => { + let str_ident = &util::to_ident(str); + quote! { #str_ident } + } + types::RefType::Map(key, value) => { + let key_ident = util::to_ident(key); + let value_ident = util::to_ident(value); + quote! { std::collections::HashMap<#key_ident, #value_ident> } + } + }, + }; + + if self.is_list() { + quote! { std::vec::Vec<#owned_type> } + } else { + owned_type + } + } + fn generate_struct_field(&self) -> TokenStream { let name_snake = self.name_snake(); - let type_name = util::to_ident(&self.to_owned_type()); - let type_ = if self.is_list() { - quote! { std::vec::Vec<#type_name> } - } else { - quote! { #type_name } - }; + let type_ = self.owned_type_ident(); let orig_name = self.name(); util::add_docs( @@ -440,11 +462,10 @@ impl types::Type { } fn borrowed_type(&self) -> TokenStream { + let type_ = self.borrowed_type_ident(); if self.should_borrow() { - let type_ = self.borrowed_type_ident(); quote! { &#type_ } } else { - let type_ = self.borrowed_type_ident(); quote! { #type_ } } } diff --git a/qbittorrent-web-api-gen/src/parser/group/method/method_tests/ref_type.check b/qbittorrent-web-api-gen/src/parser/group/method/method_tests/ref_type.check new file mode 100644 index 0000000..7a7dec4 --- /dev/null +++ b/qbittorrent-web-api-gen/src/parser/group/method/method_tests/ref_type.check @@ -0,0 +1,110 @@ +ApiMethod { + name: "plugins", + description: Some( + "The response is a JSON array of objects containing the following fields\n\n\n```JSON\n[\n {\n \"enabled\": true,\n \"fullName\": \"Legit Torrents\",\n \"name\": \"legittorrents\",\n \"supportedCategories\": [{\n \"id\": \"all\",\n \"name\": \"All categories\"\n }, {\n \"id\": \"anime\",\n \"name\": \"Anime\"\n }, {\n \"id\": \"books\",\n \"name\": \"Books\"\n }, {\n \"id\": \"games\",\n \"name\": \"Games\"\n }, {\n \"id\": \"movies\",\n \"name\": \"Movies\"\n }, {\n \"id\": \"music\",\n \"name\": \"Music\"\n }, {\n \"id\": \"tv\",\n \"name\": \"TV shows\"\n }],\n \"url\": \"http://www.legittorrents.info\",\n \"version\": \"2.3\"\n }\n]\n```", + ), + url: "plugins", + types: CompositeTypes { + composite_types: [ + Object( + TypeWithName { + name: "Category", + types: [ + String( + TypeInfo { + name: "id", + description: Some( + "Id", + ), + is_optional: false, + is_list: false, + }, + ), + String( + TypeInfo { + name: "name", + description: Some( + "Name", + ), + is_optional: false, + is_list: false, + }, + ), + ], + }, + ), + Response( + TypeWithoutName { + types: [ + Bool( + TypeInfo { + name: "enabled", + description: Some( + "Whether the plugin is enabled", + ), + is_optional: false, + is_list: false, + }, + ), + String( + TypeInfo { + name: "fullName", + description: Some( + "Full name of the plugin", + ), + is_optional: false, + is_list: false, + }, + ), + String( + TypeInfo { + name: "name", + description: Some( + "Short name of the plugin", + ), + is_optional: false, + is_list: false, + }, + ), + Object( + Object { + type_info: TypeInfo { + name: "supportedCategories", + description: Some( + "List of category objects", + ), + is_optional: false, + is_list: true, + }, + ref_type: String( + "Category", + ), + }, + ), + String( + TypeInfo { + name: "url", + description: Some( + "URL of the torrent site", + ), + is_optional: false, + is_list: false, + }, + ), + String( + TypeInfo { + name: "version", + description: Some( + "Installed version of the plugin", + ), + is_optional: false, + is_list: false, + }, + ), + ], + is_list: true, + }, + ), + ], + }, +} \ No newline at end of file diff --git a/qbittorrent-web-api-gen/src/parser/group/method/method_tests/ref_type.md b/qbittorrent-web-api-gen/src/parser/group/method/method_tests/ref_type.md new file mode 100644 index 0000000..07dd1aa --- /dev/null +++ b/qbittorrent-web-api-gen/src/parser/group/method/method_tests/ref_type.md @@ -0,0 +1,65 @@ +## Get search plugins ## + +Name: `plugins` + +**Parameters:** + +None + +**Returns:** + +HTTP Status Code | Scenario +----------------------------------|--------------------- +200 | All scenarios- see JSON below + +The response is a JSON array of objects containing the following fields + +Field | Type | Description +----------------------------------|---------|------------ +`enabled` | bool | Whether the plugin is enabled +`fullName` | string | Full name of the plugin +`name` | string | Short name of the plugin +`supportedCategories` | array | List of category objects +`url` | string | URL of the torrent site +`version` | string | Installed version of the plugin + +```JSON +[ + { + "enabled": true, + "fullName": "Legit Torrents", + "name": "legittorrents", + "supportedCategories": [{ + "id": "all", + "name": "All categories" + }, { + "id": "anime", + "name": "Anime" + }, { + "id": "books", + "name": "Books" + }, { + "id": "games", + "name": "Games" + }, { + "id": "movies", + "name": "Movies" + }, { + "id": "music", + "name": "Music" + }, { + "id": "tv", + "name": "TV shows" + }], + "url": "http://www.legittorrents.info", + "version": "2.3" + } +] +``` + +**Category object:** + +Field | Type | Description +---------------------------|---------|------------ +`id` | string | Id +`name` | string | Name diff --git a/qbittorrent-web-api-gen/src/parser/group/method/method_tests/ref_type.tree b/qbittorrent-web-api-gen/src/parser/group/method/method_tests/ref_type.tree new file mode 100644 index 0000000..2e3f921 --- /dev/null +++ b/qbittorrent-web-api-gen/src/parser/group/method/method_tests/ref_type.tree @@ -0,0 +1,276 @@ +TokenTree { + title: None, + content: [], + children: [ + TokenTree { + title: Some( + "Get search plugins", + ), + content: [ + Text( + "", + ), + Text( + "Name: `plugins`", + ), + Text( + "", + ), + Asterisk( + "Parameters:", + ), + Text( + "", + ), + Text( + "None", + ), + Text( + "", + ), + Asterisk( + "Returns:", + ), + Text( + "", + ), + Table( + Table { + header: TableRow { + raw: "HTTP Status Code | Scenario", + columns: [ + "HTTP Status Code", + "Scenario", + ], + }, + split: "----------------------------------|---------------------", + rows: [ + TableRow { + raw: "200 | All scenarios- see JSON below", + columns: [ + "200", + "All scenarios- see JSON below", + ], + }, + ], + }, + ), + Text( + "", + ), + Text( + "The response is a JSON array of objects containing the following fields", + ), + Text( + "", + ), + Table( + Table { + header: TableRow { + raw: "Field | Type | Description", + columns: [ + "Field", + "Type", + "Description", + ], + }, + split: "----------------------------------|---------|------------", + rows: [ + TableRow { + raw: "`enabled` | bool | Whether the plugin is enabled", + columns: [ + "enabled", + "bool", + "Whether the plugin is enabled", + ], + }, + TableRow { + raw: "`fullName` | string | Full name of the plugin", + columns: [ + "fullName", + "string", + "Full name of the plugin", + ], + }, + TableRow { + raw: "`name` | string | Short name of the plugin", + columns: [ + "name", + "string", + "Short name of the plugin", + ], + }, + TableRow { + raw: "`supportedCategories` | array | List of category objects", + columns: [ + "supportedCategories", + "array", + "List of category objects", + ], + }, + TableRow { + raw: "`url` | string | URL of the torrent site", + columns: [ + "url", + "string", + "URL of the torrent site", + ], + }, + TableRow { + raw: "`version` | string | Installed version of the plugin", + columns: [ + "version", + "string", + "Installed version of the plugin", + ], + }, + ], + }, + ), + Text( + "", + ), + Text( + "```JSON", + ), + Text( + "[", + ), + Text( + " {", + ), + Text( + " \"enabled\": true,", + ), + Text( + " \"fullName\": \"Legit Torrents\",", + ), + Text( + " \"name\": \"legittorrents\",", + ), + Text( + " \"supportedCategories\": [{", + ), + Text( + " \"id\": \"all\",", + ), + Text( + " \"name\": \"All categories\"", + ), + Text( + " }, {", + ), + Text( + " \"id\": \"anime\",", + ), + Text( + " \"name\": \"Anime\"", + ), + Text( + " }, {", + ), + Text( + " \"id\": \"books\",", + ), + Text( + " \"name\": \"Books\"", + ), + Text( + " }, {", + ), + Text( + " \"id\": \"games\",", + ), + Text( + " \"name\": \"Games\"", + ), + Text( + " }, {", + ), + Text( + " \"id\": \"movies\",", + ), + Text( + " \"name\": \"Movies\"", + ), + Text( + " }, {", + ), + Text( + " \"id\": \"music\",", + ), + Text( + " \"name\": \"Music\"", + ), + Text( + " }, {", + ), + Text( + " \"id\": \"tv\",", + ), + Text( + " \"name\": \"TV shows\"", + ), + Text( + " }],", + ), + Text( + " \"url\": \"http://www.legittorrents.info\",", + ), + Text( + " \"version\": \"2.3\"", + ), + Text( + " }", + ), + Text( + "]", + ), + Text( + "```", + ), + Text( + "", + ), + Asterisk( + "Category object:", + ), + Text( + "", + ), + Table( + Table { + header: TableRow { + raw: "Field | Type | Description", + columns: [ + "Field", + "Type", + "Description", + ], + }, + split: "---------------------------|---------|------------", + rows: [ + TableRow { + raw: "`id` | string | Id", + columns: [ + "id", + "string", + "Id", + ], + }, + TableRow { + raw: "`name` | string | Name", + columns: [ + "name", + "string", + "Name", + ], + }, + ], + }, + ), + ], + children: [], + }, + ], +} \ No newline at end of file diff --git a/qbittorrent-web-api-gen/src/parser/group/method/method_tests/search_result.check b/qbittorrent-web-api-gen/src/parser/group/method/method_tests/search_result.check index 44fc18c..fc24550 100644 --- a/qbittorrent-web-api-gen/src/parser/group/method/method_tests/search_result.check +++ b/qbittorrent-web-api-gen/src/parser/group/method/method_tests/search_result.check @@ -133,7 +133,9 @@ ApiMethod { is_optional: false, is_list: true, }, - ref_type: "", + ref_type: String( + "Result", + ), }, ), String( diff --git a/qbittorrent-web-api-gen/src/parser/group/method/mod.rs b/qbittorrent-web-api-gen/src/parser/group/method/mod.rs index 6788151..7d53d47 100644 --- a/qbittorrent-web-api-gen/src/parser/group/method/mod.rs +++ b/qbittorrent-web-api-gen/src/parser/group/method/mod.rs @@ -422,4 +422,9 @@ mod tests { fn array_field() { run_test!("array_field"); } + + #[test] + fn ref_type() { + run_test!("ref_type"); + } } diff --git a/qbittorrent-web-api-gen/src/types.rs b/qbittorrent-web-api-gen/src/types.rs index 565dcc1..d2b70ef 100644 --- a/qbittorrent-web-api-gen/src/types.rs +++ b/qbittorrent-web-api-gen/src/types.rs @@ -31,10 +31,16 @@ impl TypeInfo { } } +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum RefType { + String(String), + Map(String, String), +} + #[derive(Debug, Clone)] pub struct Object { pub type_info: TypeInfo, - pub ref_type: String, + pub ref_type: RefType, } #[derive(Debug, Clone)] @@ -63,17 +69,6 @@ pub enum Type { } impl Type { - pub fn to_owned_type(&self) -> String { - match self { - Type::Number(_) => "i128".into(), - Type::Float(_) => "f32".into(), - Type::Bool(_) => "bool".into(), - Type::String(_) => "String".into(), - Type::StringArray(_) => "String".into(), - Type::Object(_) => "String".into(), - } - } - pub fn to_borrowed_type(&self) -> String { match self { Type::Number(_) => "i32".into(), @@ -81,7 +76,7 @@ impl Type { Type::Bool(_) => "bool".into(), Type::String(_) => "str".into(), Type::StringArray(_) => "&[str]".into(), - Type::Object(_) => "str".into(), + Type::Object(_) => todo!(), } } @@ -136,10 +131,10 @@ impl Type { ) }; - let create_object_type = |name: &str| { + let create_object_type = |ref_type: RefType| { Some(Type::Object(Object { type_info: create_type_info(), - ref_type: name.to_camel(), + ref_type, })) }; @@ -150,30 +145,85 @@ impl Type { "string" => Some(Type::String(create_type_info())), "array" => description .extract_type() - .and_then(|t| create_object_type(&t)) + .and_then(create_object_type) .or_else(|| Some(Type::StringArray(create_type_info()))), "float" => Some(Type::Float(create_type_info())), - name => create_object_type(name), + name => description + .extract_type() + .and_then(create_object_type) + .or_else(|| { + let n = if name.is_empty() { + "String".into() + } else { + name.into() + }; + + create_object_type(RefType::String(n)) + }), } } } trait ExtractType { - fn extract_type(&self) -> Option; + fn extract_type(&self) -> Option; } impl ExtractType for Option { - fn extract_type(&self) -> Option { - self.as_ref().and_then(|t| { - let re = RegexBuilder::new(r".*Array of (\w+) objects.*") - .case_insensitive(true) - .build() - .unwrap(); + fn extract_type(&self) -> Option { + let list_type = || { + self.as_ref().and_then(|t| { + let re = RegexBuilder::new(r"(?:Array|List) of (\w+) objects") + .case_insensitive(true) + .build() + .unwrap(); - let cap = re.captures(t)?; + let cap = re.captures(t)?; - cap.get(1).map(|m| m.as_str().to_camel()) - }) + cap.get(1) + .map(|m| m.as_str().to_camel()) + .map(RefType::String) + }) + }; + + let map_type = || { + self.as_ref().and_then(|t| { + let re = RegexBuilder::new(r"map from (\w+) to (\w+) object") + .case_insensitive(true) + .build() + .unwrap(); + + let cap = re.captures(t)?; + let key_type = match cap.get(1).map(|m| m.as_str().to_camel()) { + Some(k) => k, + None => return None, + }; + let value_type = match cap.get(2).map(|m| m.as_str().to_camel()) { + Some(v) => v, + None => return None, + }; + + Some(RefType::Map(key_type, value_type)) + }) + }; + + let object_type = || { + self.as_ref().and_then(|t| { + let re = RegexBuilder::new(r"(\w+) object see table below") + .case_insensitive(true) + .build() + .unwrap(); + + let cap = re.captures(t)?; + let object_type = match cap.get(1).map(|m| m.as_str().to_camel()) { + Some(k) => k, + None => return None, + }; + + Some(RefType::String(object_type)) + }) + }; + + list_type().or_else(map_type).or_else(object_type) } } @@ -185,6 +235,6 @@ mod tests { fn test_regex() { let input = Some("Array of result objects- see table below".to_string()); let res = input.extract_type(); - assert_eq!(res.unwrap(), "Result"); + assert_eq!(res.unwrap(), RefType::String("Result".into())); } } diff --git a/qbittorrent-web-api-gen/token_tree.txt b/qbittorrent-web-api-gen/token_tree.txt index 46c7841..0e4a9f3 100644 --- a/qbittorrent-web-api-gen/token_tree.txt +++ b/qbittorrent-web-api-gen/token_tree.txt @@ -4497,17 +4497,17 @@ TokenTree { Table( Table { header: TableRow { - raw: "Property | Type | Description", + raw: "Property | Type | Description", columns: [ "Property", "Type", "Description", ], }, - split: "------------------------------|---------|------------", + split: "--------------------------------|-----------|------------", rows: [ TableRow { - raw: "`rid` | integer | Response ID", + raw: "`rid` | integer | Response ID", columns: [ "rid", "integer", @@ -4515,67 +4515,67 @@ TokenTree { ], }, TableRow { - raw: "`full_update` | bool | Whether the response contains all the data or partial data", + raw: "`full_update`_optional_ | bool | Whether the response contains all the data or partial data", columns: [ - "full_update", + "full_update_optional_", "bool", "Whether the response contains all the data or partial data", ], }, TableRow { - raw: "`torrents` | object | Property: torrent hash, value: same as [torrent list](#get-torrent-list)", + raw: "`torrents`_optional_ | object | Property: torrent hash, value: same as [torrent list](#get-torrent-list), map from string to torrents object", columns: [ - "torrents", + "torrents_optional_", "object", - "Property: torrent hash, value: same as [torrent list](#get-torrent-list)", + "Property: torrent hash, value: same as [torrent list](#get-torrent-list), map from string to torrents object", ], }, TableRow { - raw: "`torrents_removed` | array | List of hashes of torrents removed since last request", + raw: "`torrents_removed`_optional_ | array | List of hashes of torrents removed since last request", columns: [ - "torrents_removed", + "torrents_removed_optional_", "array", "List of hashes of torrents removed since last request", ], }, TableRow { - raw: "`categories` | object | Info for categories added since last request", + raw: "`categories`_optional_ | object | Info for categories added since last request, map from string to categories object", columns: [ - "categories", + "categories_optional_", "object", - "Info for categories added since last request", + "Info for categories added since last request, map from string to categories object", ], }, TableRow { - raw: "`categories_removed` | array | List of categories removed since last request", + raw: "`categories_removed`_optional_ | array | List of categories removed since last request", columns: [ - "categories_removed", + "categories_removed_optional_", "array", "List of categories removed since last request", ], }, TableRow { - raw: "`tags` | array | List of tags added since last request", + raw: "`tags`_optional_ | array | List of tags added since last request", columns: [ - "tags", + "tags_optional_", "array", "List of tags added since last request", ], }, TableRow { - raw: "`tags_removed` | array | List of tags removed since last request", + raw: "`tags_removed`_optional_ | array | List of tags removed since last request", columns: [ - "tags_removed", + "tags_removed_optional_", "array", "List of tags removed since last request", ], }, TableRow { - raw: "`server_state` | object | Global transfer info", + raw: "`server_state`_optional_ | object | `server_state` object see table below", columns: [ - "server_state", + "server_state_optional_", "object", - "Global transfer info", + "server_state object see table below", ], }, ], @@ -4629,6 +4629,502 @@ TokenTree { Text( "", ), + Asterisk( + "ServerState object:", + ), + Text( + "", + ), + Table( + Table { + header: TableRow { + raw: "Property | Type | Description", + columns: [ + "Property", + "Type", + "Description", + ], + }, + split: "------------------------------|---------|------------", + rows: [ + TableRow { + raw: "`average_time_queue` | integer | Average time queue", + columns: [ + "average_time_queue", + "integer", + "Average time queue", + ], + }, + TableRow { + raw: "`dl_info_data` | number | Download info data", + columns: [ + "dl_info_data", + "number", + "Download info data", + ], + }, + TableRow { + raw: "`dl_info_speed` | number | Download info speed", + columns: [ + "dl_info_speed", + "number", + "Download info speed", + ], + }, + TableRow { + raw: "`queued_io_jobs` | integer | Queued io jobs", + columns: [ + "queued_io_jobs", + "integer", + "Queued io jobs", + ], + }, + TableRow { + raw: "`total_buffers_size` | number | Total buffers size", + columns: [ + "total_buffers_size", + "number", + "Total buffers size", + ], + }, + TableRow { + raw: "`total_peer_connections` | integer | Total peer connections", + columns: [ + "total_peer_connections", + "integer", + "Total peer connections", + ], + }, + ], + }, + ), + Text( + "", + ), + Asterisk( + "Categories object:", + ), + Text( + "", + ), + Table( + Table { + header: TableRow { + raw: "Property | Type | Description", + columns: [ + "Property", + "Type", + "Description", + ], + }, + split: "------------------------------|---------|------------", + rows: [ + TableRow { + raw: "`name` | string | Category name", + columns: [ + "name", + "string", + "Category name", + ], + }, + TableRow { + raw: "`savePath` | string | Save path", + columns: [ + "savePath", + "string", + "Save path", + ], + }, + ], + }, + ), + Text( + "", + ), + Asterisk( + "Torrents object:", + ), + Text( + "", + ), + Table( + Table { + header: TableRow { + raw: "Property | Type | Description", + columns: [ + "Property", + "Type", + "Description", + ], + }, + split: "--------------------------------|-----------|------------", + rows: [ + TableRow { + raw: "`added_on`_optional_ | integer | Time (Unix Epoch) when the torrent was added to the client", + columns: [ + "added_on_optional_", + "integer", + "Time (Unix Epoch) when the torrent was added to the client", + ], + }, + TableRow { + raw: "`amount_left`_optional_ | integer | Amount of data left to download (bytes)", + columns: [ + "amount_left_optional_", + "integer", + "Amount of data left to download (bytes)", + ], + }, + TableRow { + raw: "`auto_tmm`_optional_ | bool | Whether this torrent is managed by Automatic Torrent Management", + columns: [ + "auto_tmm_optional_", + "bool", + "Whether this torrent is managed by Automatic Torrent Management", + ], + }, + TableRow { + raw: "`availability`_optional_ | float | Percentage of file pieces currently available", + columns: [ + "availability_optional_", + "float", + "Percentage of file pieces currently available", + ], + }, + TableRow { + raw: "`category`_optional_ | string | Category of the torrent", + columns: [ + "category_optional_", + "string", + "Category of the torrent", + ], + }, + TableRow { + raw: "`completed`_optional_ | integer | Amount of transfer data completed (bytes)", + columns: [ + "completed_optional_", + "integer", + "Amount of transfer data completed (bytes)", + ], + }, + TableRow { + raw: "`completion_on`_optional_ | integer | Time (Unix Epoch) when the torrent completed", + columns: [ + "completion_on_optional_", + "integer", + "Time (Unix Epoch) when the torrent completed", + ], + }, + TableRow { + raw: "`content_path`_optional_ | string | Absolute path of torrent content (root path for multifile torrents, absolute file path for singlefile torrents)", + columns: [ + "content_path_optional_", + "string", + "Absolute path of torrent content (root path for multifile torrents, absolute file path for singlefile torrents)", + ], + }, + TableRow { + raw: "`dl_limit`_optional_ | integer | Torrent download speed limit (bytes/s). `-1` if ulimited.", + columns: [ + "dl_limit_optional_", + "integer", + "Torrent download speed limit (bytes/s). -1 if ulimited.", + ], + }, + TableRow { + raw: "`dlspeed`_optional_ | integer | Torrent download speed (bytes/s)", + columns: [ + "dlspeed_optional_", + "integer", + "Torrent download speed (bytes/s)", + ], + }, + TableRow { + raw: "`downloaded`_optional_ | integer | Amount of data downloaded", + columns: [ + "downloaded_optional_", + "integer", + "Amount of data downloaded", + ], + }, + TableRow { + raw: "`downloaded_session`_optional_ | integer | Amount of data downloaded this session", + columns: [ + "downloaded_session_optional_", + "integer", + "Amount of data downloaded this session", + ], + }, + TableRow { + raw: "`eta`_optional_ | integer | Torrent ETA (seconds)", + columns: [ + "eta_optional_", + "integer", + "Torrent ETA (seconds)", + ], + }, + TableRow { + raw: "`f_l_piece_prio`_optional_ | bool | True if first last piece are prioritized", + columns: [ + "f_l_piece_prio_optional_", + "bool", + "True if first last piece are prioritized", + ], + }, + TableRow { + raw: "`force_start`_optional_ | bool | True if force start is enabled for this torrent", + columns: [ + "force_start_optional_", + "bool", + "True if force start is enabled for this torrent", + ], + }, + TableRow { + raw: "`hash`_optional_ | string | Torrent hash", + columns: [ + "hash_optional_", + "string", + "Torrent hash", + ], + }, + TableRow { + raw: "`last_activity`_optional_ | integer | Last time (Unix Epoch) when a chunk was downloaded/uploaded", + columns: [ + "last_activity_optional_", + "integer", + "Last time (Unix Epoch) when a chunk was downloaded/uploaded", + ], + }, + TableRow { + raw: "`magnet_uri`_optional_ | string | Magnet URI corresponding to this torrent", + columns: [ + "magnet_uri_optional_", + "string", + "Magnet URI corresponding to this torrent", + ], + }, + TableRow { + raw: "`max_ratio`_optional_ | float | Maximum share ratio until torrent is stopped from seeding/uploading", + columns: [ + "max_ratio_optional_", + "float", + "Maximum share ratio until torrent is stopped from seeding/uploading", + ], + }, + TableRow { + raw: "`max_seeding_time`_optional_ | integer | Maximum seeding time (seconds) until torrent is stopped from seeding", + columns: [ + "max_seeding_time_optional_", + "integer", + "Maximum seeding time (seconds) until torrent is stopped from seeding", + ], + }, + TableRow { + raw: "`name`_optional_ | string | Torrent name", + columns: [ + "name_optional_", + "string", + "Torrent name", + ], + }, + TableRow { + raw: "`num_complete`_optional_ | integer | Number of seeds in the swarm", + columns: [ + "num_complete_optional_", + "integer", + "Number of seeds in the swarm", + ], + }, + TableRow { + raw: "`num_incomplete`_optional_ | integer | Number of leechers in the swarm", + columns: [ + "num_incomplete_optional_", + "integer", + "Number of leechers in the swarm", + ], + }, + TableRow { + raw: "`num_leechs`_optional_ | integer | Number of leechers connected to", + columns: [ + "num_leechs_optional_", + "integer", + "Number of leechers connected to", + ], + }, + TableRow { + raw: "`num_seeds`_optional_ | integer | Number of seeds connected to", + columns: [ + "num_seeds_optional_", + "integer", + "Number of seeds connected to", + ], + }, + TableRow { + raw: "`priority`_optional_ | integer | Torrent priority. Returns -1 if queuing is disabled or torrent is in seed mode", + columns: [ + "priority_optional_", + "integer", + "Torrent priority. Returns -1 if queuing is disabled or torrent is in seed mode", + ], + }, + TableRow { + raw: "`progress`_optional_ | float | Torrent progress (percentage/100)", + columns: [ + "progress_optional_", + "float", + "Torrent progress (percentage/100)", + ], + }, + TableRow { + raw: "`ratio`_optional_ | float | Torrent share ratio. Max ratio value: 9999.", + columns: [ + "ratio_optional_", + "float", + "Torrent share ratio. Max ratio value: 9999.", + ], + }, + TableRow { + raw: "`ratio_limit`_optional_ | float | TODO (what is different from `max_ratio`?)", + columns: [ + "ratio_limit_optional_", + "float", + "TODO (what is different from max_ratio?)", + ], + }, + TableRow { + raw: "`save_path`_optional_ | string | Path where this torrent's data is stored", + columns: [ + "save_path_optional_", + "string", + "Path where this torrent's data is stored", + ], + }, + TableRow { + raw: "`seeding_time`_optional_ | integer | Torrent elapsed time while complete (seconds)", + columns: [ + "seeding_time_optional_", + "integer", + "Torrent elapsed time while complete (seconds)", + ], + }, + TableRow { + raw: "`seeding_time_limit`_optional_ | integer | TODO (what is different from `max_seeding_time`?) seeding_time_limit is a per torrent setting, when Automatic Torrent Management is disabled, furthermore then max_seeding_time is set to seeding_time_limit for this torrent. If Automatic Torrent Management is enabled, the value is -2. And if max_seeding_time is unset it have a default value -1.", + columns: [ + "seeding_time_limit_optional_", + "integer", + "TODO (what is different from max_seeding_time?) seeding_time_limit is a per torrent setting, when Automatic Torrent Management is disabled, furthermore then max_seeding_time is set to seeding_time_limit for this torrent. If Automatic Torrent Management is enabled, the value is -2. And if max_seeding_time is unset it have a default value -1.", + ], + }, + TableRow { + raw: "`seen_complete`_optional_ | integer | Time (Unix Epoch) when this torrent was last seen complete", + columns: [ + "seen_complete_optional_", + "integer", + "Time (Unix Epoch) when this torrent was last seen complete", + ], + }, + TableRow { + raw: "`seq_dl`_optional_ | bool | True if sequential download is enabled", + columns: [ + "seq_dl_optional_", + "bool", + "True if sequential download is enabled", + ], + }, + TableRow { + raw: "`size`_optional_ | integer | Total size (bytes) of files selected for download", + columns: [ + "size_optional_", + "integer", + "Total size (bytes) of files selected for download", + ], + }, + TableRow { + raw: "`state`_optional_ | string | Torrent state. See table here below for the possible values", + columns: [ + "state_optional_", + "string", + "Torrent state. See table here below for the possible values", + ], + }, + TableRow { + raw: "`super_seeding`_optional_ | bool | True if super seeding is enabled", + columns: [ + "super_seeding_optional_", + "bool", + "True if super seeding is enabled", + ], + }, + TableRow { + raw: "`tags`_optional_ | string | Comma-concatenated tag list of the torrent", + columns: [ + "tags_optional_", + "string", + "Comma-concatenated tag list of the torrent", + ], + }, + TableRow { + raw: "`time_active`_optional_ | integer | Total active time (seconds)", + columns: [ + "time_active_optional_", + "integer", + "Total active time (seconds)", + ], + }, + TableRow { + raw: "`total_size`_optional_ | integer | Total size (bytes) of all file in this torrent (including unselected ones)", + columns: [ + "total_size_optional_", + "integer", + "Total size (bytes) of all file in this torrent (including unselected ones)", + ], + }, + TableRow { + raw: "`tracker`_optional_ | string | The first tracker with working status. Returns empty string if no tracker is working.", + columns: [ + "tracker_optional_", + "string", + "The first tracker with working status. Returns empty string if no tracker is working.", + ], + }, + TableRow { + raw: "`up_limit`_optional_ | integer | Torrent upload speed limit (bytes/s). `-1` if ulimited.", + columns: [ + "up_limit_optional_", + "integer", + "Torrent upload speed limit (bytes/s). -1 if ulimited.", + ], + }, + TableRow { + raw: "`uploaded`_optional_ | integer | Amount of data uploaded", + columns: [ + "uploaded_optional_", + "integer", + "Amount of data uploaded", + ], + }, + TableRow { + raw: "`uploaded_session`_optional_ | integer | Amount of data uploaded this session", + columns: [ + "uploaded_session_optional_", + "integer", + "Amount of data uploaded this session", + ], + }, + TableRow { + raw: "`upspeed`_optional_ | integer | Torrent upload speed (bytes/s)", + columns: [ + "upspeed_optional_", + "integer", + "Torrent upload speed (bytes/s)", + ], + }, + ], + }, + ), + Text( + "", + ), ], children: [], }, @@ -8171,9 +8667,10 @@ TokenTree { ], }, TableRow { - raw: "`deleteFiles` | If set to `true`, the downloaded data will also be deleted, otherwise has no effect.", + raw: "`deleteFiles` | bool | If set to `true`, the downloaded data will also be deleted, otherwise has no effect.", columns: [ "deleteFiles", + "bool", "If set to true, the downloaded data will also be deleted, otherwise has no effect.", ], }, @@ -14637,6 +15134,46 @@ TokenTree { Text( "", ), + Asterisk( + "Category object:", + ), + Text( + "", + ), + Table( + Table { + header: TableRow { + raw: "Field | Type | Description", + columns: [ + "Field", + "Type", + "Description", + ], + }, + split: "---------------------------|---------|------------", + rows: [ + TableRow { + raw: "`id` | string | Id", + columns: [ + "id", + "string", + "Id", + ], + }, + TableRow { + raw: "`name` | string | Name", + columns: [ + "name", + "string", + "Name", + ], + }, + ], + }, + ), + Text( + "", + ), ], children: [], }, From fb1327a14000687cee42d5a37415bff891531e8e Mon Sep 17 00:00:00 2001 From: Joel Wachsler Date: Sat, 23 Jul 2022 00:26:23 +0000 Subject: [PATCH 44/47] Update test --- qbittorrent-web-api-gen/tests/search_types.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/qbittorrent-web-api-gen/tests/search_types.rs b/qbittorrent-web-api-gen/tests/search_types.rs index efd57a2..4a21fbd 100644 --- a/qbittorrent-web-api-gen/tests/search_types.rs +++ b/qbittorrent-web-api-gen/tests/search_types.rs @@ -12,10 +12,8 @@ async fn main() -> Result<()> { let api = Api::login(BASE_URL, USERNAME, PASSWORD).await?; let _ = api.search().install_plugin("https://raw.githubusercontent.com/qbittorrent/search-plugins/master/nova3/engines/legittorrents.py").await?; - let plugins = api.search().plugins().await?; - eprintln!("{:?}", plugins); - // let _ = api.search().results(1).send().await?; - // let _ = api.search().delete(1).await?; + // just check that the deserialization works + let _ = api.search().plugins().await?; Ok(()) } From d4b4661e0261ffb3970a64901c16f87f54963dc0 Mon Sep 17 00:00:00 2001 From: Joel Wachsler Date: Sat, 23 Jul 2022 00:27:30 +0000 Subject: [PATCH 45/47] Remove unused files --- .../group/method/method_with_params.rs | 328 ------------------ .../group/method/method_without_params.rs | 27 -- .../src/generate/group/method/mod.rs | 72 ---- .../src/generate/group/method/return_type.rs | 203 ----------- .../group/method/send_method_builder.rs | 98 ------ 5 files changed, 728 deletions(-) delete mode 100644 qbittorrent-web-api-gen/src/generate/group/method/method_with_params.rs delete mode 100644 qbittorrent-web-api-gen/src/generate/group/method/method_without_params.rs delete mode 100644 qbittorrent-web-api-gen/src/generate/group/method/mod.rs delete mode 100644 qbittorrent-web-api-gen/src/generate/group/method/return_type.rs delete mode 100644 qbittorrent-web-api-gen/src/generate/group/method/send_method_builder.rs diff --git a/qbittorrent-web-api-gen/src/generate/group/method/method_with_params.rs b/qbittorrent-web-api-gen/src/generate/group/method/method_with_params.rs deleted file mode 100644 index 5796699..0000000 --- a/qbittorrent-web-api-gen/src/generate/group/method/method_with_params.rs +++ /dev/null @@ -1,328 +0,0 @@ -use std::rc::Rc; - -use case::CaseExt; -use proc_macro2::TokenStream; -use quote::quote; - -use crate::{ - generate::util, - parser::{self, ApiMethod, ApiParameters}, - types, -}; - -use super::{ - return_type::create_return_type, send_method_builder::SendMethodBuilder, MethodsAndExtra, -}; - -pub fn create_method_with_params( - group: &parser::ApiGroup, - method: &parser::ApiMethod, - params: &parser::ApiParameters, - method_name: &proc_macro2::Ident, - url: &str, -) -> MethodsAndExtra { - let param_type = util::to_ident(&format!( - "{}{}Parameters", - group.name.to_camel(), - method.name.to_camel() - )); - - let parameters = Parameters::new(params); - let has_optional_parameters = !parameters.optional.is_empty(); - let generator = MethodGenerator { - group, - url, - parameters, - param_type, - method, - method_name, - }; - - if has_optional_parameters { - generator.generate_method_with_builder() - } else { - generator.generate_method_without_builder() - } -} - -#[derive(Debug)] -struct MethodGenerator<'a> { - group: &'a parser::ApiGroup, - url: &'a str, - parameters: Parameters<'a>, - param_type: proc_macro2::Ident, - method: &'a ApiMethod, - method_name: &'a proc_macro2::Ident, -} - -impl<'a> MethodGenerator<'a> { - fn generate_method_without_builder(&self) -> MethodsAndExtra { - let form_builder = self.parameters.mandatory.form_builder(); - let form_attributes = - quote! { .multipart(reqwest::multipart::Form::new()#(#form_builder)*) }; - - let builder = SendMethodBuilder::new(self.method_name, self.url, quote! { self.auth }) - .description(&self.method.description) - .with_args(&self.parameters.mandatory.generate_params()) - .with_extra_form_args(&[form_attributes]); - - match create_return_type(self.group, self.method) { - Some((return_type_name, return_type)) => { - MethodsAndExtra::new(builder.return_type(&return_type_name).build()) - .with_structs(return_type) - } - None => MethodsAndExtra::new(builder.build()), - } - } - - fn generate_method_with_builder(&self) -> MethodsAndExtra { - let group_name = self.group_name(); - let send_builder = self.send_builder(&util::to_ident("send")); - let send_impl_generator = - SendImplGenerator::new(&group_name, &self.parameters, &self.param_type); - - let send = match create_return_type(self.group, self.method) { - Some((return_type_name, return_type)) => { - let send_impl = - send_impl_generator.generate(send_builder.return_type(&return_type_name)); - - quote! { - #send_impl - #return_type - } - } - None => send_impl_generator.generate(send_builder), - }; - let builder = generate_builder( - &self.parameters, - self.method, - self.method_name, - &self.param_type, - ); - let param_type = &self.param_type; - - let group_impl = quote! { - pub struct #param_type<'a> { - group: &'a #group_name<'a>, - form: reqwest::multipart::Form, - } - - #send - }; - - MethodsAndExtra::new(builder).with_structs(group_impl) - } - - fn group_name(&self) -> proc_macro2::Ident { - util::to_ident(&self.group.name.to_camel()) - } - - fn send_builder(&self, name: &proc_macro2::Ident) -> SendMethodBuilder { - SendMethodBuilder::new(name, self.url, quote! { self.group.auth }).with_form() - } -} - -fn generate_builder( - parameters: &Parameters, - method: &ApiMethod, - method_name: &proc_macro2::Ident, - param_type: &proc_macro2::Ident, -) -> proc_macro2::TokenStream { - let mandatory_param_names = parameters.mandatory.names(); - let mandatory_param_args = parameters.mandatory.generate_params(); - - util::add_docs( - &method.description, - quote! { - pub fn #method_name(&self, #(#mandatory_param_args),*) -> #param_type { - #param_type::new(self, #(#mandatory_param_names),*) - } - }, - ) -} - -#[derive(Debug)] -struct SendImplGenerator<'a> { - group_name: &'a proc_macro2::Ident, - parameters: &'a Parameters<'a>, - param_type: &'a proc_macro2::Ident, -} - -impl<'a> SendImplGenerator<'a> { - fn new( - group_name: &'a proc_macro2::Ident, - parameters: &'a Parameters<'a>, - param_type: &'a proc_macro2::Ident, - ) -> Self { - Self { - group_name, - parameters, - param_type, - } - } - - fn generate(&self, send_method_builder: SendMethodBuilder) -> TokenStream { - let parameters = self.parameters; - - let optional_builder_methods = parameters.optional.generate_builder_methods(); - let mandatory_param_form_build = parameters.mandatory.form_builder(); - let mandatory_param_args = parameters.mandatory.generate_params(); - let param_type = self.param_type; - let group_name = self.group_name; - let send_method = send_method_builder.build(); - - quote! { - impl<'a> #param_type<'a> { - fn new(group: &'a #group_name, #(#mandatory_param_args),*) -> Self { - let form = reqwest::multipart::Form::new()#(#mandatory_param_form_build)*; - Self { group, form } - } - - #(#optional_builder_methods)* - #send_method - } - } - } -} - -#[derive(Debug)] -struct Parameters<'a> { - mandatory: MandatoryParams<'a>, - optional: OptionalParams<'a>, -} - -impl<'a> Parameters<'a> { - fn new(api_parameters: &'a ApiParameters) -> Self { - let rc_params = Rc::new(api_parameters); - - let mandatory = MandatoryParams::new(&rc_params); - let optional = OptionalParams::new(&rc_params); - - Self { - mandatory, - optional, - } - } -} - -#[derive(Debug)] -struct MandatoryParams<'a> { - params: Vec>, -} - -impl<'a> MandatoryParams<'a> { - fn new(params: &'a ApiParameters) -> Self { - Self { - params: Parameter::from(¶ms.mandatory), - } - } - - fn generate_params(&self) -> Vec { - self.params - .iter() - .map(|p| p.generate_param_with_name()) - .collect() - } - - fn form_builder(&self) -> Vec { - self.params - .iter() - .map(|param| { - let name_ident = param.name_ident(); - let name = param.name(); - quote! { .text(#name, #name_ident.to_string()) } - }) - .collect() - } - - fn names(&self) -> Vec { - self.params - .iter() - .map(|p| p.name_ident()) - .map(|name_ident| quote! { #name_ident }) - .collect() - } -} - -#[derive(Debug)] -struct OptionalParams<'a> { - params: Vec>, -} - -impl<'a> OptionalParams<'a> { - fn new(params: &'a ApiParameters) -> Self { - Self { - params: Parameter::from(¶ms.optional), - } - } - - fn is_empty(&self) -> bool { - self.params.is_empty() - } - - fn generate_builder_methods(&self) -> Vec { - self.params - .iter() - .map(Self::generate_builder_method) - .collect() - } - - fn generate_builder_method(param: &Parameter) -> TokenStream { - let name = param.name(); - let name_ident = param.name_ident(); - - let param_type = util::to_ident(¶m.p_type.to_borrowed_type()); - - let builder_param = if param.p_type.should_borrow() { - quote! { &#param_type } - } else { - quote! { #param_type } - }; - - util::add_docs( - ¶m.p_type.get_type_info().description, - quote! { - pub fn #name_ident(mut self, value: #builder_param) -> Self { - self.form = self.form.text(#name, value.to_string()); - self - } - }, - ) - } -} - -#[derive(Debug)] -struct Parameter<'a> { - p_type: &'a types::Type, -} - -impl<'a> Parameter<'a> { - fn new(p_type: &'a types::Type) -> Self { - Self { p_type } - } - - fn from(parameters: &[types::Type]) -> Vec> { - parameters.iter().map(Parameter::new).collect() - } - - fn name(&self) -> String { - self.p_type.get_type_info().name.to_snake() - } - - fn name_ident(&self) -> proc_macro2::Ident { - util::to_ident(&self.name()) - } - - fn generate_param_with_name(&self) -> TokenStream { - let t = util::to_ident(&self.p_type.to_borrowed_type()); - - let name_ident = self.name_ident(); - let t = if self.p_type.should_borrow() { - quote! { &#t } - } else { - quote! { #t } - }; - - quote! { #name_ident: #t } - } -} diff --git a/qbittorrent-web-api-gen/src/generate/group/method/method_without_params.rs b/qbittorrent-web-api-gen/src/generate/group/method/method_without_params.rs deleted file mode 100644 index ec1d3a7..0000000 --- a/qbittorrent-web-api-gen/src/generate/group/method/method_without_params.rs +++ /dev/null @@ -1,27 +0,0 @@ -use quote::quote; - -use super::{ - return_type::create_return_type, send_method_builder::SendMethodBuilder, MethodsAndExtra, -}; -use crate::parser; - -pub fn create_method_without_params( - group: &parser::ApiGroup, - method: &parser::ApiMethod, - method_name: proc_macro2::Ident, - url: &str, -) -> MethodsAndExtra { - let builder = SendMethodBuilder::new(&method_name, url, quote! { self.auth }) - .description(&method.description); - - match create_return_type(group, method) { - Some((return_type_name, return_type)) => { - MethodsAndExtra::new(builder.return_type(&return_type_name).build()) - .with_structs(return_type) - } - None => { - // assume that all methods without a return type returns a string - MethodsAndExtra::new(builder.build()) - } - } -} diff --git a/qbittorrent-web-api-gen/src/generate/group/method/mod.rs b/qbittorrent-web-api-gen/src/generate/group/method/mod.rs deleted file mode 100644 index 041cec4..0000000 --- a/qbittorrent-web-api-gen/src/generate/group/method/mod.rs +++ /dev/null @@ -1,72 +0,0 @@ -mod method_with_params; -mod method_without_params; -mod return_type; -mod send_method_builder; - -use crate::{generate::util, parser}; -use case::CaseExt; -use quote::quote; - -use self::{ - method_with_params::create_method_with_params, - method_without_params::create_method_without_params, -}; - -pub fn generate_methods( - group: &parser::ApiGroup, - auth: &syn::Ident, - group_name_camel: &syn::Ident, -) -> proc_macro2::TokenStream { - let methods_and_extra = group - .methods - .iter() - .map(|method| generate_method(group, method)); - - let methods = methods_and_extra - .clone() - .map(|MethodsAndExtra { methods, .. }| methods); - - let extra = methods_and_extra.flat_map(|MethodsAndExtra { extra: structs, .. }| structs); - - quote! { - impl <'a> #group_name_camel<'a> { - pub fn new(auth: &'a #auth) -> Self { - Self { auth } - } - - #(#methods)* - } - - #(#extra)* - } -} - -#[derive(Debug)] -pub struct MethodsAndExtra { - methods: proc_macro2::TokenStream, - extra: Option, -} - -impl MethodsAndExtra { - pub fn new(methods: proc_macro2::TokenStream) -> Self { - Self { - methods, - extra: None, - } - } - - pub fn with_structs(mut self, structs: proc_macro2::TokenStream) -> Self { - self.extra = Some(structs); - self - } -} - -fn generate_method(group: &parser::ApiGroup, method: &parser::ApiMethod) -> MethodsAndExtra { - let method_name = util::to_ident(&method.name.to_snake()); - let url = format!("/api/v2/{}/{}", group.url, method.url); - - match &method.parameters { - Some(params) => create_method_with_params(group, method, params, &method_name, &url), - None => create_method_without_params(group, method, method_name, &url), - } -} diff --git a/qbittorrent-web-api-gen/src/generate/group/method/return_type.rs b/qbittorrent-web-api-gen/src/generate/group/method/return_type.rs deleted file mode 100644 index cba375b..0000000 --- a/qbittorrent-web-api-gen/src/generate/group/method/return_type.rs +++ /dev/null @@ -1,203 +0,0 @@ -use std::collections::HashMap; - -use case::CaseExt; -use quote::{format_ident, quote}; -use regex::Regex; - -use crate::{generate::util, parser, types}; - -pub fn create_return_type( - group: &parser::ApiGroup, - method: &parser::ApiMethod, -) -> Option<(proc_macro2::TokenStream, proc_macro2::TokenStream)> { - let return_type = match &method.return_type { - Some(t) => t, - None => return None, - }; - - let to_enum_name = |name: &str| to_enum_name(&group.name, &method.name, name); - - let enum_types_with_names: Vec<(String, proc_macro2::TokenStream)> = - create_enum_with_names(return_type, &group.name, &method.name); - - let enum_names: HashMap = enum_types_with_names - .iter() - .map(|(enum_name, _)| (enum_name.clone(), to_enum_name(enum_name))) - .collect(); - - let enum_types = enum_types_with_names.iter().map(|(_, enum_type)| enum_type); - - let builder_fields = return_type - .parameters - .iter() - .map(|parameter| generate_builder_field(parameter, &enum_names)); - - let return_type_name = util::to_ident(&format!( - "{}{}Result", - &group.name.to_camel(), - &method.name.to_camel() - )); - - let result_type = if return_type.is_list { - quote! { std::vec::Vec<#return_type_name> } - } else { - quote! { #return_type_name } - }; - - Some(( - result_type, - quote! { - #[derive(Debug, Deserialize)] - pub struct #return_type_name { - #(#builder_fields,)* - } - - #(#enum_types)* - }, - )) -} - -fn create_enum_with_names( - return_type: &parser::ReturnType, - group_name: &str, - method_name: &str, -) -> Vec<(String, proc_macro2::TokenStream)> { - return_type - .parameters - .iter() - .flat_map(create_enum_fields) - .map(|(name, enum_fields)| create_enum(enum_fields, group_name, method_name, name)) - .collect() -} - -fn create_enum( - enum_fields: Vec, - group_name: &str, - method_name: &str, - name: String, -) -> (String, proc_macro2::TokenStream) { - let enum_name = util::to_ident(&to_enum_name(group_name, method_name, &name)); - ( - name, - quote! { - #[allow(clippy::enum_variant_names)] - #[derive(Debug, Deserialize, PartialEq, Eq)] - pub enum #enum_name { - #(#enum_fields,)* - } - }, - ) -} - -fn create_enum_fields( - parameter: &parser::ReturnTypeParameter, -) -> Option<(String, Vec)> { - match ¶meter.return_type { - types::Type::Number(types::TypeInfo { - ref name, - type_description: Some(type_description), - .. - }) => create_enum_field_value(type_description, name, create_number_enum_value), - types::Type::String(types::TypeInfo { - ref name, - type_description: Some(type_description), - .. - }) => create_enum_field_value(type_description, name, create_string_enum_value), - _ => None, - } -} - -fn generate_builder_field( - parameter: &parser::ReturnTypeParameter, - enum_names: &HashMap, -) -> proc_macro2::TokenStream { - let name_string = ¶meter.name; - let name = util::to_ident(&name_string.to_snake().replace("__", "_")); - let enum_name = match enum_names.get(name_string) { - Some(enum_type) => enum_type.to_owned(), - None => parameter.return_type.to_owned_type(), - }; - let return_type = util::to_ident(&enum_name); - let return_type_as_quote = if parameter.return_type.is_list() { - quote! { std::vec::Vec<#return_type> } - } else { - quote! { #return_type } - }; - let generate_field = |field_name| { - quote! { - #[serde(rename = #name_string)] - pub #field_name: #return_type_as_quote - } - }; - - // "type" is a reserved keyword in Rust, so we just add "t_" to it. - if name_string == "type" { - generate_field(format_ident!("t_{}", name)) - } else { - generate_field(name) - } -} - -fn create_enum_field_value( - type_description: &types::TypeDescription, - name: &str, - f: F, -) -> Option<(String, Vec)> -where - F: Fn(&types::TypeDescriptions) -> proc_macro2::TokenStream, -{ - let enum_fields: Vec = type_description - .values - .iter() - .map(f) - .collect::>(); - - let nn = name.to_string(); - - Some((nn, enum_fields)) -} - -fn create_string_enum_value( - type_description: &types::TypeDescriptions, -) -> proc_macro2::TokenStream { - let value = &type_description.value; - let value_as_ident = util::to_ident(&value.to_camel()); - create_enum_field(&value_as_ident, value, &type_description.description) -} - -fn create_number_enum_value(value: &types::TypeDescriptions) -> proc_macro2::TokenStream { - let v = &value.value; - let re = Regex::new(r#"\(.*\)"#).unwrap(); - let desc = &value - .description - .replace(' ', "_") - .replace('-', "_") - .replace(',', "_"); - let desc_without_parentheses = re.replace_all(desc, ""); - let ident = util::to_ident(&desc_without_parentheses.to_camel()); - - create_enum_field(&ident, v, &value.description) -} - -fn create_enum_field( - ident: &syn::Ident, - rename: &str, - description: &str, -) -> proc_macro2::TokenStream { - util::add_docs( - &Some(description.to_string()), - quote! { - #[serde(rename = #rename)] - #ident - }, - ) -} - -fn to_enum_name(group_name: &str, method_name: &str, name: &str) -> String { - format!( - "{}{}{}", - group_name.to_camel(), - method_name.to_camel(), - name.to_camel() - ) -} diff --git a/qbittorrent-web-api-gen/src/generate/group/method/send_method_builder.rs b/qbittorrent-web-api-gen/src/generate/group/method/send_method_builder.rs deleted file mode 100644 index ffd3ad8..0000000 --- a/qbittorrent-web-api-gen/src/generate/group/method/send_method_builder.rs +++ /dev/null @@ -1,98 +0,0 @@ -use quote::quote; - -use crate::generate::util; - -pub struct SendMethodBuilder { - method_name: syn::Ident, - url: String, - auth_module_path: proc_macro2::TokenStream, - return_type: Option, - description: Option, - args: Vec, - extra_form_args: Vec, - form: bool, -} - -impl SendMethodBuilder { - pub fn new( - method_name: &syn::Ident, - url: &str, - auth_module_path: proc_macro2::TokenStream, - ) -> Self { - Self { - method_name: method_name.clone(), - url: url.to_string(), - auth_module_path, - return_type: None, - description: None, - form: false, - args: vec![], - extra_form_args: vec![], - } - } - - pub fn return_type(mut self, value: &proc_macro2::TokenStream) -> Self { - self.return_type = Some(value.clone()); - self - } - - pub fn description(mut self, value: &Option) -> Self { - self.description = value.clone(); - self - } - - pub fn with_form(mut self) -> Self { - self.form = true; - self - } - - pub fn with_args(mut self, value: &[proc_macro2::TokenStream]) -> Self { - self.args = value.to_vec(); - self - } - - pub fn with_extra_form_args(mut self, value: &[proc_macro2::TokenStream]) -> Self { - self.extra_form_args = value.to_vec(); - self - } - - pub fn build(&self) -> proc_macro2::TokenStream { - let method_name = &self.method_name; - let (return_type, parse_type) = match &self.return_type { - Some(t) => (t.clone(), quote! { .json::<#t>() }), - None => (quote! { String }, quote! { .text() }), - }; - let url = &self.url; - let auth_module_path = &self.auth_module_path; - let form = if self.form { - quote! { .multipart(self.form) } - } else { - quote! {} - }; - let arg_list = &self.args; - let args = if !arg_list.is_empty() { - quote! { , #(#arg_list),* } - } else { - quote! {} - }; - let extra_form_args = &self.extra_form_args; - - util::add_docs( - &self.description, - quote! { - pub async fn #method_name(self #args) -> Result<#return_type> { - let res = #auth_module_path - .authenticated_client(#url) - #form - #(#extra_form_args)* - .send() - .await? - #parse_type - .await?; - - Ok(res) - } - }, - ) - } -} From 273ed0a52ab3385c5f7f1f59b3461688fc43c5a1 Mon Sep 17 00:00:00 2001 From: Joel Wachsler Date: Sat, 23 Jul 2022 00:38:00 +0000 Subject: [PATCH 46/47] Refactor --- .../src/generate/api_group.rs | 89 ++++ .../src/generate/api_method.rs | 31 ++ qbittorrent-web-api-gen/src/generate/group.rs | 184 +++++++ .../src/generate/group/mod.rs | 472 ------------------ .../src/generate/group_method.rs | 186 +++++++ qbittorrent-web-api-gen/src/generate/mod.rs | 3 + 6 files changed, 493 insertions(+), 472 deletions(-) create mode 100644 qbittorrent-web-api-gen/src/generate/api_group.rs create mode 100644 qbittorrent-web-api-gen/src/generate/api_method.rs create mode 100644 qbittorrent-web-api-gen/src/generate/group.rs delete mode 100644 qbittorrent-web-api-gen/src/generate/group/mod.rs create mode 100644 qbittorrent-web-api-gen/src/generate/group_method.rs diff --git a/qbittorrent-web-api-gen/src/generate/api_group.rs b/qbittorrent-web-api-gen/src/generate/api_group.rs new file mode 100644 index 0000000..26abae1 --- /dev/null +++ b/qbittorrent-web-api-gen/src/generate/api_group.rs @@ -0,0 +1,89 @@ +use crate::parser; +use case::CaseExt; +use proc_macro2::{Ident, TokenStream}; +use quote::quote; + +use super::{group_method::GroupMethod, skeleton::auth_ident, util}; + +impl parser::ApiGroup { + pub fn generate(&self) -> TokenStream { + let struct_name = self.struct_name(); + let group_name_snake = self.name_snake(); + let group_methods = self.generate_group_methods(); + + let group_struct = self.group_struct(); + let group_factory = self.group_factory(); + let auth = auth_ident(); + + quote! { + pub mod #group_name_snake { + impl <'a> #struct_name<'a> { + pub fn new(auth: &'a super::#auth) -> Self { + Self { auth } + } + } + + #group_struct + #group_factory + + #(#group_methods)* + } + } + } + + fn generate_group_methods(&self) -> Vec { + let group_methods = self.group_methods(); + group_methods + .iter() + .map(|group_method| group_method.generate_method()) + .collect() + } + + fn group_factory(&self) -> TokenStream { + let struct_name = self.struct_name(); + let name_snake = self.name_snake(); + let auth = auth_ident(); + + util::add_docs( + &self.description, + quote! { + impl super::#auth { + pub fn #name_snake(&self) -> #struct_name { + #struct_name::new(self) + } + } + }, + ) + } + + fn group_struct(&self) -> TokenStream { + let struct_name = self.struct_name(); + let auth = auth_ident(); + + quote! { + #[derive(Debug)] + pub struct #struct_name<'a> { + auth: &'a super::#auth, + } + } + } + + fn group_methods(&self) -> Vec { + self.methods + .iter() + .map(|method| GroupMethod::new(self, method)) + .collect() + } + + pub fn struct_name(&self) -> Ident { + self.name_camel() + } + + fn name_camel(&self) -> Ident { + util::to_ident(&self.name.to_camel()) + } + + fn name_snake(&self) -> Ident { + util::to_ident(&self.name.to_snake()) + } +} diff --git a/qbittorrent-web-api-gen/src/generate/api_method.rs b/qbittorrent-web-api-gen/src/generate/api_method.rs new file mode 100644 index 0000000..abdb8cf --- /dev/null +++ b/qbittorrent-web-api-gen/src/generate/api_method.rs @@ -0,0 +1,31 @@ +use case::CaseExt; +use proc_macro2::{Ident, TokenStream}; +use quote::quote; + +use crate::parser; + +use super::util; + +impl parser::ApiMethod { + pub fn structs(&self) -> TokenStream { + let objects = self.types.objects(); + let structs = objects.iter().map(|obj| obj.generate_struct()); + + quote! { + #(#structs)* + } + } + + pub fn enums(&self) -> TokenStream { + let enums = self.types.enums(); + let generated_enums = enums.iter().map(|e| e.generate()); + + quote! { + #(#generated_enums)* + } + } + + pub fn name_snake(&self) -> Ident { + util::to_ident(&self.name.to_snake()) + } +} diff --git a/qbittorrent-web-api-gen/src/generate/group.rs b/qbittorrent-web-api-gen/src/generate/group.rs new file mode 100644 index 0000000..f2988bf --- /dev/null +++ b/qbittorrent-web-api-gen/src/generate/group.rs @@ -0,0 +1,184 @@ +use crate::{parser, types}; +use case::CaseExt; +use proc_macro2::{Ident, TokenStream}; +use quote::quote; + +use super::util; + +pub fn generate_groups(groups: Vec) -> TokenStream { + let gr = groups + .iter() + // implemented manually + .filter(|group| group.name != "authentication") + .map(generate_group); + + quote! { + #(#gr)* + } +} + +fn generate_group(group: &parser::ApiGroup) -> TokenStream { + let group = group.generate(); + + quote! { + #group + } +} + +impl parser::TypeWithName { + pub fn generate_struct(&self) -> TokenStream { + let fields = self.types.iter().map(|obj| obj.generate_struct_field()); + let name = util::to_ident(&self.name); + + quote! { + #[derive(Debug, serde::Deserialize)] + pub struct #name { + #(#fields,)* + } + } + } +} + +impl types::Type { + pub fn generate_struct_field(&self) -> TokenStream { + let name_snake = self.name_snake(); + let type_ = self.owned_type_ident(); + let orig_name = self.name(); + + util::add_docs( + &self.get_type_info().description, + quote! { + #[serde(rename = #orig_name)] + pub #name_snake: #type_ + }, + ) + } + + fn owned_type_ident(&self) -> TokenStream { + let owned_type = match self { + types::Type::Number(_) => quote! { i128 }, + types::Type::Float(_) => quote! { f32 }, + types::Type::Bool(_) => quote! { bool }, + types::Type::String(_) => quote! { String }, + types::Type::StringArray(_) => quote! { String }, + types::Type::Object(obj) => match &obj.ref_type { + types::RefType::String(str) => { + let str_ident = &util::to_ident(str); + quote! { #str_ident } + } + types::RefType::Map(key, value) => { + let key_ident = util::to_ident(key); + let value_ident = util::to_ident(value); + quote! { std::collections::HashMap<#key_ident, #value_ident> } + } + }, + }; + + if self.is_list() { + quote! { std::vec::Vec<#owned_type> } + } else { + owned_type + } + } + + fn name(&self) -> String { + self.get_type_info().name.clone() + } + + fn name_snake(&self) -> Ident { + util::to_ident(&self.name().to_snake()) + } +} + +impl parser::Enum { + pub fn generate(&self) -> TokenStream { + let values = self.values.iter().map(|enum_value| enum_value.generate()); + let name = util::to_ident(&self.name); + + quote! { + #[allow(clippy::enum_variant_names)] + #[derive(Debug, serde::Deserialize, PartialEq, Eq)] + pub enum #name { + #(#values,)* + } + } + } +} + +impl parser::EnumValue { + fn generate(&self) -> TokenStream { + util::add_docs(&self.description, self.generate_field()) + } + + fn generate_field(&self) -> TokenStream { + let orig_name = self.original_value.clone(); + + // special enum value which does not follow conventions + if orig_name == "\"/path/to/download/to\"" { + quote! { + PathToDownloadTo(String) + } + } else { + let name_camel = self.name_camel(); + quote! { + #[serde(rename = #orig_name)] + #name_camel + } + } + } + + fn name_camel(&self) -> Ident { + util::to_ident(&self.value.to_camel()) + } +} + +impl types::Type { + pub fn generate_optional_builder_method_with_docs(&self) -> TokenStream { + util::add_docs( + &self.get_type_info().description, + self.generate_optional_builder_method(), + ) + } + + fn borrowed_type_ident(&self) -> Ident { + util::to_ident(&self.to_borrowed_type()) + } + + pub fn to_parameter(&self) -> TokenStream { + let name_snake = self.name_snake(); + let borrowed_type = self.borrowed_type(); + + quote! { #name_snake: #borrowed_type } + } + + pub fn generate_form_builder(&self, add_to: TokenStream) -> TokenStream { + let name_str = self.name(); + let name_snake = self.name_snake(); + + quote! { + #add_to = #add_to.text(#name_str, #name_snake.to_string()); + } + } + + fn generate_optional_builder_method(&self) -> TokenStream { + let name_snake = self.name_snake(); + let borrowed_type = self.borrowed_type(); + let form_builder = self.generate_form_builder(quote! { self.form }); + + quote! { + pub fn #name_snake(mut self, #name_snake: #borrowed_type) -> Self { + #form_builder; + self + } + } + } + + fn borrowed_type(&self) -> TokenStream { + let type_ = self.borrowed_type_ident(); + if self.should_borrow() { + quote! { &#type_ } + } else { + quote! { #type_ } + } + } +} diff --git a/qbittorrent-web-api-gen/src/generate/group/mod.rs b/qbittorrent-web-api-gen/src/generate/group/mod.rs deleted file mode 100644 index 111b0fc..0000000 --- a/qbittorrent-web-api-gen/src/generate/group/mod.rs +++ /dev/null @@ -1,472 +0,0 @@ -use crate::{parser, types}; -use case::CaseExt; -use proc_macro2::{Ident, TokenStream}; -use quote::quote; - -use super::{skeleton::auth_ident, util}; - -pub fn generate_groups(groups: Vec) -> TokenStream { - let gr = groups - .iter() - // implemented manually - .filter(|group| group.name != "authentication") - .map(generate_group); - - quote! { - #(#gr)* - } -} - -fn generate_group(group: &parser::ApiGroup) -> TokenStream { - let group = group.generate(); - - quote! { - #group - } -} - -impl parser::ApiGroup { - fn generate(&self) -> TokenStream { - let struct_name = self.struct_name(); - let group_name_snake = self.name_snake(); - let group_methods = self.generate_group_methods(); - - let group_struct = self.group_struct(); - let group_factory = self.group_factory(); - let auth = auth_ident(); - - quote! { - pub mod #group_name_snake { - impl <'a> #struct_name<'a> { - pub fn new(auth: &'a super::#auth) -> Self { - Self { auth } - } - } - - #group_struct - #group_factory - - #(#group_methods)* - } - } - } - - fn generate_group_methods(&self) -> Vec { - let group_methods = self.group_methods(); - group_methods - .iter() - .map(|group_method| group_method.generate_method()) - .collect() - } - - fn group_factory(&self) -> TokenStream { - let struct_name = self.struct_name(); - let name_snake = self.name_snake(); - let auth = auth_ident(); - - util::add_docs( - &self.description, - quote! { - impl super::#auth { - pub fn #name_snake(&self) -> #struct_name { - #struct_name::new(self) - } - } - }, - ) - } - - fn group_struct(&self) -> TokenStream { - let struct_name = self.struct_name(); - let auth = auth_ident(); - - quote! { - #[derive(Debug)] - pub struct #struct_name<'a> { - auth: &'a super::#auth, - } - } - } - - fn group_methods(&self) -> Vec { - self.methods - .iter() - .map(|method| GroupMethod::new(self, method)) - .collect() - } - - fn struct_name(&self) -> Ident { - self.name_camel() - } - - fn name_camel(&self) -> Ident { - util::to_ident(&self.name.to_camel()) - } - - fn name_snake(&self) -> Ident { - util::to_ident(&self.name.to_snake()) - } -} - -impl parser::ApiMethod { - fn structs(&self) -> TokenStream { - let objects = self.types.objects(); - let structs = objects.iter().map(|obj| obj.generate_struct()); - - quote! { - #(#structs)* - } - } - - fn enums(&self) -> TokenStream { - let enums = self.types.enums(); - let generated_enums = enums.iter().map(|e| e.generate()); - - quote! { - #(#generated_enums)* - } - } - - fn name_snake(&self) -> Ident { - util::to_ident(&self.name.to_snake()) - } -} - -impl parser::TypeWithName { - fn generate_struct(&self) -> TokenStream { - let fields = self.types.iter().map(|obj| obj.generate_struct_field()); - let name = util::to_ident(&self.name); - - quote! { - #[derive(Debug, serde::Deserialize)] - pub struct #name { - #(#fields,)* - } - } - } -} - -impl types::Type { - fn owned_type_ident(&self) -> TokenStream { - let owned_type = match self { - types::Type::Number(_) => quote! { i128 }, - types::Type::Float(_) => quote! { f32 }, - types::Type::Bool(_) => quote! { bool }, - types::Type::String(_) => quote! { String }, - types::Type::StringArray(_) => quote! { String }, - types::Type::Object(obj) => match &obj.ref_type { - types::RefType::String(str) => { - let str_ident = &util::to_ident(str); - quote! { #str_ident } - } - types::RefType::Map(key, value) => { - let key_ident = util::to_ident(key); - let value_ident = util::to_ident(value); - quote! { std::collections::HashMap<#key_ident, #value_ident> } - } - }, - }; - - if self.is_list() { - quote! { std::vec::Vec<#owned_type> } - } else { - owned_type - } - } - - fn generate_struct_field(&self) -> TokenStream { - let name_snake = self.name_snake(); - let type_ = self.owned_type_ident(); - let orig_name = self.name(); - - util::add_docs( - &self.get_type_info().description, - quote! { - #[serde(rename = #orig_name)] - pub #name_snake: #type_ - }, - ) - } - - fn name(&self) -> String { - self.get_type_info().name.clone() - } - - fn name_snake(&self) -> Ident { - util::to_ident(&self.name().to_snake()) - } -} - -impl parser::Enum { - fn generate(&self) -> TokenStream { - let values = self.values.iter().map(|enum_value| enum_value.generate()); - let name = util::to_ident(&self.name); - - quote! { - #[allow(clippy::enum_variant_names)] - #[derive(Debug, serde::Deserialize, PartialEq, Eq)] - pub enum #name { - #(#values,)* - } - } - } -} - -impl parser::EnumValue { - fn generate(&self) -> TokenStream { - util::add_docs(&self.description, self.generate_field()) - } - - fn generate_field(&self) -> TokenStream { - let orig_name = self.original_value.clone(); - - // special enum value which does not follow conventions - if orig_name == "\"/path/to/download/to\"" { - quote! { - PathToDownloadTo(String) - } - } else { - let name_camel = self.name_camel(); - quote! { - #[serde(rename = #orig_name)] - #name_camel - } - } - } - - fn name_camel(&self) -> Ident { - util::to_ident(&self.value.to_camel()) - } -} - -#[derive(Debug)] -struct GroupMethod<'a> { - group: &'a parser::ApiGroup, - method: &'a parser::ApiMethod, -} - -impl<'a> GroupMethod<'a> { - fn new(group: &'a parser::ApiGroup, method: &'a parser::ApiMethod) -> Self { - Self { group, method } - } - - fn generate_method(&self) -> TokenStream { - let method_name = self.method.name_snake(); - let structs = self.method.structs(); - let enums = self.method.enums(); - let builder = self.generate_request_builder(); - let response_struct = self.generate_response_struct(); - let request_method = self.generate_request_method(); - - quote! { - pub mod #method_name { - #structs - #enums - #builder - #response_struct - #request_method - } - } - } - - fn generate_request_method(&self) -> TokenStream { - let method_name = self.method.name_snake(); - - let parameters = self - .method - .types - .mandatory_params() - .iter() - .map(|param| param.to_parameter()) - .collect(); - - let form_builder = self.mandatory_parameters_as_form_builder(); - - let method_impl = if self.method.types.optional_parameters().is_empty() { - self.generate_send_method( - &method_name, - parameters, - quote! { self.auth }, - quote! { form }, - quote! { - let form = reqwest::multipart::Form::new(); - #form_builder - }, - ) - } else { - quote! { - pub fn #method_name(&self, #(#parameters),*) -> Builder<'_> { - let form = reqwest::multipart::Form::new(); - #form_builder - Builder { group: self, form } - } - } - }; - - let group_struct_name = self.group.struct_name(); - let method_impl_with_docs = util::add_docs(&self.method.description, method_impl); - - quote! { - impl<'a> super::#group_struct_name<'a> { - #method_impl_with_docs - } - } - } - - fn generate_response_struct(&self) -> TokenStream { - let response = match self.method.types.response() { - Some(res) => res, - None => return quote! {}, - }; - - let struct_fields = response - .types - .iter() - .map(|field| field.generate_struct_field()); - - quote! { - #[derive(Debug, serde::Deserialize)] - pub struct Response { - #(#struct_fields,)* - } - } - } - - /// Returns a TokenStream containing a request builder if there are optional - /// parameters, otherwise an empty TokenStream is returned. - fn generate_request_builder(&self) -> TokenStream { - let optional_params = self.method.types.optional_parameters(); - if optional_params.is_empty() { - return quote! {}; - } - - let builder_methods = optional_params - .iter() - .map(|param| param.generate_optional_builder_method_with_docs()); - - let group_name = self.group.struct_name(); - let send_method = self.generate_send_method( - &util::to_ident("send"), - vec![], - quote! { self.group.auth }, - quote! { self.form }, - quote! {}, - ); - - quote! { - pub struct Builder<'a> { - group: &'a super::#group_name<'a>, - form: reqwest::multipart::Form, - } - - impl<'a> Builder<'a> { - #send_method - #(#builder_methods)* - } - } - } - - fn generate_send_method( - &self, - method_name: &Ident, - parameters: Vec, - auth_access: TokenStream, - form_access: TokenStream, - form_factory: TokenStream, - ) -> TokenStream { - let method_url = format!("/api/v2/{}/{}", self.group.url, self.method.url); - - let (response_type, response_parse) = match self.method.types.response() { - Some(resp) => { - if resp.is_list { - ( - quote! { std::vec::Vec }, - quote! { .json::>() }, - ) - } else { - (quote! { Response }, quote! { .json::() }) - } - } - None => (quote! { String }, quote! { .text() }), - }; - - quote! { - pub async fn #method_name(self, #(#parameters),*) -> super::super::Result<#response_type> { - #form_factory - let res = #auth_access - .authenticated_client(#method_url) - .multipart(#form_access) - .send() - .await? - #response_parse - .await?; - - Ok(res) - } - } - } - - fn mandatory_parameters_as_form_builder(&self) -> TokenStream { - let builder = self - .method - .types - .mandatory_params() - .into_iter() - .map(|param| param.generate_form_builder(quote! { form })); - - quote! { - #(let #builder)* - } - } -} - -impl types::Type { - fn generate_optional_builder_method_with_docs(&self) -> TokenStream { - util::add_docs( - &self.get_type_info().description, - self.generate_optional_builder_method(), - ) - } - - fn borrowed_type_ident(&self) -> Ident { - util::to_ident(&self.to_borrowed_type()) - } - - fn to_parameter(&self) -> TokenStream { - let name_snake = self.name_snake(); - let borrowed_type = self.borrowed_type(); - - quote! { #name_snake: #borrowed_type } - } - - fn generate_form_builder(&self, add_to: TokenStream) -> TokenStream { - let name_str = self.name(); - let name_snake = self.name_snake(); - - quote! { - #add_to = #add_to.text(#name_str, #name_snake.to_string()); - } - } - - fn generate_optional_builder_method(&self) -> TokenStream { - let name_snake = self.name_snake(); - let borrowed_type = self.borrowed_type(); - let form_builder = self.generate_form_builder(quote! { self.form }); - - quote! { - pub fn #name_snake(mut self, #name_snake: #borrowed_type) -> Self { - #form_builder; - self - } - } - } - - fn borrowed_type(&self) -> TokenStream { - let type_ = self.borrowed_type_ident(); - if self.should_borrow() { - quote! { &#type_ } - } else { - quote! { #type_ } - } - } -} diff --git a/qbittorrent-web-api-gen/src/generate/group_method.rs b/qbittorrent-web-api-gen/src/generate/group_method.rs new file mode 100644 index 0000000..e8fb818 --- /dev/null +++ b/qbittorrent-web-api-gen/src/generate/group_method.rs @@ -0,0 +1,186 @@ +use crate::parser; +use proc_macro2::{Ident, TokenStream}; +use quote::quote; + +use super::util; + +#[derive(Debug)] +pub struct GroupMethod<'a> { + group: &'a parser::ApiGroup, + method: &'a parser::ApiMethod, +} + +impl<'a> GroupMethod<'a> { + pub fn new(group: &'a parser::ApiGroup, method: &'a parser::ApiMethod) -> Self { + Self { group, method } + } + + pub fn generate_method(&self) -> TokenStream { + let method_name = self.method.name_snake(); + let structs = self.method.structs(); + let enums = self.method.enums(); + let builder = self.generate_request_builder(); + let response_struct = self.generate_response_struct(); + let request_method = self.generate_request_method(); + + quote! { + pub mod #method_name { + #structs + #enums + #builder + #response_struct + #request_method + } + } + } + + fn generate_request_method(&self) -> TokenStream { + let method_name = self.method.name_snake(); + + let parameters = self + .method + .types + .mandatory_params() + .iter() + .map(|param| param.to_parameter()) + .collect(); + + let form_builder = self.mandatory_parameters_as_form_builder(); + + let method_impl = if self.method.types.optional_parameters().is_empty() { + self.generate_send_method( + &method_name, + parameters, + quote! { self.auth }, + quote! { form }, + quote! { + let form = reqwest::multipart::Form::new(); + #form_builder + }, + ) + } else { + quote! { + pub fn #method_name(&self, #(#parameters),*) -> Builder<'_> { + let form = reqwest::multipart::Form::new(); + #form_builder + Builder { group: self, form } + } + } + }; + + let group_struct_name = self.group.struct_name(); + let method_impl_with_docs = util::add_docs(&self.method.description, method_impl); + + quote! { + impl<'a> super::#group_struct_name<'a> { + #method_impl_with_docs + } + } + } + + fn generate_response_struct(&self) -> TokenStream { + let response = match self.method.types.response() { + Some(res) => res, + None => return quote! {}, + }; + + let struct_fields = response + .types + .iter() + .map(|field| field.generate_struct_field()); + + quote! { + #[derive(Debug, serde::Deserialize)] + pub struct Response { + #(#struct_fields,)* + } + } + } + + /// Returns a TokenStream containing a request builder if there are optional + /// parameters, otherwise an empty TokenStream is returned. + fn generate_request_builder(&self) -> TokenStream { + let optional_params = self.method.types.optional_parameters(); + if optional_params.is_empty() { + return quote! {}; + } + + let builder_methods = optional_params + .iter() + .map(|param| param.generate_optional_builder_method_with_docs()); + + let group_name = self.group.struct_name(); + let send_method = self.generate_send_method( + &util::to_ident("send"), + vec![], + quote! { self.group.auth }, + quote! { self.form }, + quote! {}, + ); + + quote! { + pub struct Builder<'a> { + group: &'a super::#group_name<'a>, + form: reqwest::multipart::Form, + } + + impl<'a> Builder<'a> { + #send_method + #(#builder_methods)* + } + } + } + + fn generate_send_method( + &self, + method_name: &Ident, + parameters: Vec, + auth_access: TokenStream, + form_access: TokenStream, + form_factory: TokenStream, + ) -> TokenStream { + let method_url = format!("/api/v2/{}/{}", self.group.url, self.method.url); + + let (response_type, response_parse) = match self.method.types.response() { + Some(resp) => { + if resp.is_list { + ( + quote! { std::vec::Vec }, + quote! { .json::>() }, + ) + } else { + (quote! { Response }, quote! { .json::() }) + } + } + None => (quote! { String }, quote! { .text() }), + }; + + quote! { + pub async fn #method_name(self, #(#parameters),*) -> super::super::Result<#response_type> { + #form_factory + let res = #auth_access + .authenticated_client(#method_url) + .multipart(#form_access) + .send() + .await? + #response_parse + .await?; + + Ok(res) + } + } + } + + fn mandatory_parameters_as_form_builder(&self) -> TokenStream { + let builder = self + .method + .types + .mandatory_params() + .into_iter() + .map(|param| param.generate_form_builder(quote! { form })); + + quote! { + #(let #builder)* + } + } +} diff --git a/qbittorrent-web-api-gen/src/generate/mod.rs b/qbittorrent-web-api-gen/src/generate/mod.rs index 9e68fa9..f6fb78d 100644 --- a/qbittorrent-web-api-gen/src/generate/mod.rs +++ b/qbittorrent-web-api-gen/src/generate/mod.rs @@ -1,6 +1,9 @@ mod group; +mod group_method; mod skeleton; mod util; +mod api_method; +mod api_group; use case::CaseExt; use proc_macro2::TokenStream; From 4070215aac17305be0b2f54e8f9fb4ce4a3e11ec Mon Sep 17 00:00:00 2001 From: Joel Wachsler Date: Sat, 23 Jul 2022 00:40:30 +0000 Subject: [PATCH 47/47] Format --- qbittorrent-web-api-gen/src/generate/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qbittorrent-web-api-gen/src/generate/mod.rs b/qbittorrent-web-api-gen/src/generate/mod.rs index f6fb78d..7292d8a 100644 --- a/qbittorrent-web-api-gen/src/generate/mod.rs +++ b/qbittorrent-web-api-gen/src/generate/mod.rs @@ -1,9 +1,9 @@ +mod api_group; +mod api_method; mod group; mod group_method; mod skeleton; mod util; -mod api_method; -mod api_group; use case::CaseExt; use proc_macro2::TokenStream;