2026-01-13 4.3.1
  - Officially support Python 3.14.
  - Include dead flatbencode dependency for easier distro packaging.


2025-02-24 4.3.0
  - Torf.read_stream() can now read `bytes` and `bytearray` objects in addition to file-like
    objects.
  - Provide type annotations for the public API.


2024-06-13 4.2.7
  - Exclude tests from the package.


2024-03-25 4.2.6
  - Validate creation date if it exists.


2024-03-09 4.2.5
  - Bugfix: Include symbolic links in the torrent's files.


2023-12-04 4.2.4
  - Bugfix: Remove hardcoded minimum and maximum piece sizes from
    Torrent.calculate_piece_size().


2023-12-01 4.2.3
  - Torrent.calculate_piece_size() now returns 16 MiB for content sizes bigger
    than 16 GiB. (Thanks @cannibalChipper)


2023-09-11 4.2.2
  - Fix a bug that was introduced in 4.2.0. Instead of forcibly decoding all
    encodings as UTF-8, go back to defaulting to undecoded bytes (like before)
    and only perform a decode-and-replace-invalid-characters routine on known
    strings like ["info"]["name"].


2023-07-02 4.2.1
  - Setting Torrent.piece_size_min/max now also sets Torrent.piece_size if it is
    too small/big.


2023-04-16 4.2.0
  - When reading torrent files, strings are now always decoded as UTF-8 (except
    for ["info"]["pieces"]). This makes it harder to store binary data in
    non-standard fields, but it also means ["info"]["name"] is always a unicode
    string.
  - Allow any "piece length" that is divisible by 16 KiB.
    Previously, power of 2 was required.


2023-01-26 4.1.4
  - Fix "Too many open files" error when creating a torrent with loads of small
    files.


2023-01-09 4.1.3
  - Try to reduce memory usage before being out of memory.
  - Terminate piece hashing threads if they are idle for more than
    500 milliseconds.


2022-11-24 4.1.2
  - Bugfix: Torrent's piece_size_min and piece_size_max arguments are no longer
    ignored.
  - Torrent.piece_size_min and Torrent.piece_size_max are now properties. They
    default to the new class attributes piece_size_min_default and
    piece_size_max_default.
  - Torrent.calculate_piece_size(): New arguments: min_size, max_size specify
    the minimum and maximum piece size.


2022-11-15 4.1.1
  - Bugfix: Don't crash if "creation date" is something weird like an empty
    string.


2022-11-09 4.1.0
  - Torrent now accepts piece_size_min and piece_size_max arguments.
  - Bugfix: Don't reuse a torrent that has a smaller piece_size than
    piece_size_min.


2022-09-22 4.0.4
  - Bugfix: Expect non-standard fields (e.g. "md5sum") in file list when reusing
    torrent.


2022-07-02 4.0.3
  - Bugfix: Copy file order from reused torrent.


2022-06-19 4.0.2
  - Bugfix: Don't reuse a torrent that has a bigger piece_size than
    piece_size_max.


2022-05-17 4.0.1
  - Bugfix: RecursionError when pickling File objects


2022-05-05 4.0.0
  - Torrent.verify(): The "skip_on_error" argument was removed.
  - The new TorrentFileStream class lets you operate on a torrent's stream of
    concatenated files.
  - The new attribute Torrent.location provides the file system path without the
    torrent's name.
  - The new Torrent.reuse() method copies piece hashes from an existing torrent
    file with the same name and file tree. It can also find a matching torrent
    in a bunch of directories.


2020-10-29 3.1.3
  - Bugfix: Exclude tests from package.


2020-10-25 3.1.2
  - Bugfix: Preserve binary values of fields that aren't part of the BitTorrent
    specification.
    (Thanks, @ayasechan)


2020-09-26 3.1.1
  - Bugfix: Fix poor performance when torrent contains huge number of files
    (Thanks, @mon)


2020-08-11 3.1.0
  - Bugfix: Gracefully handle empty string for "url-list" and other URL lists in
    metainfo
  - The new properties Torrent.include_globs and Torrent.include_regexs can be
    used to keep files even if they match an exclude pattern.


2020-06-20 3.0.2
  - Bugfix: Torrent.validate() and Torrent.read_stream() now raise MetainfoError
    if the "info" field is not a dictionary.
  - Bugfix: Magnet.from_string() raised ValueError instead of MagnetError if the
    "xl" parameter wasn't a number.
  - Bugfix: Magnet.from_string() strips whitespace from the beginning and end
    before parsing the URI.
  - Bugfix: Magnet.kt used commas to separate keywords. (I don't know why.)
  - Bugfix: Gracefully handle empty path components in torrent file
    (e.g. "foo//bar")
  - Torrent.private is now None instead of False if there is no "private" field
    in the "info" section of the metainfo.


2020-04-07 3.0.1
  - Make things work with Python 3.6.
  - Magnet.as_torrent is now a method called Magnet.torrent().


2020-04-02 3.0.0
  - Depend on flatbencode instead of bencoder.pyx
  - Bug fixed: Setting the "private" property to False removed the flag from the
    metainfo which could potentially change the info hash if a torrent file had
    the flag explicitly disabled.
  - Bug fixed: Torrent.read() validated if the "validate" argument was False
  - Hashing pieces uses multiple threads for better performance.
  - Support for the "md5sum" field was dropped.  Calculating MD5 hashes besides
    the SHA1 hashes is no longer easily possible due to multithreading and it's
    unclear to me if/how this field is even useful.
  - The new methods Torrent.verify_content() and Torrent.verify_filesize() check
    if on-disk data matches a given torrent file.
  - The property Torrent.exclude was replaced by Torrent.exclude_globs and
    Torrent.exclude_regexs.  These return special lists that filter files when
    changed.
  - Torrent.path is a path-like object.
  - Torrent.files, Torrent.filepaths, Torrent.trackers, Torrent.webseeds and
    Torrent.httpseeds are mutable lists of path-like objects or URLs that
    automatically synchronize with Torrent.metainfo when changed.
  - Torrent.filetree uses File objects as leaf nodes.  File is a path-like
    object that also stores the file size.
  - The new class attributes Torrent.piece_size_min and Torrent.piece_size_max
    can be used to quickly specify piece size limits.  Setting the piece_size
    property to an out-of-bounds piece size or returning one with
    Torrent.calculate_piece_size() raises PieceSizeError.
  - Torrent.validate() is better at finding invalid stuff in the metainfo.
  - Exceptions were added and removed.  If you don't catch TorfError, make sure
    you're expecting the correct exceptions.
  - Except for ReadError and WriteError, exceptions no longer have an "errno"
    property.
  - When setting the Torrent.path property to None, only "pieces" is removed
    from the metainfo.  "piece length", "pieces", "length" and "files" are kept.
    "name" is only changed when a new path is set.
  - The license was changed to GPLv3.


2019-07-01 2.1.0
  - Keep piece size smaller for large torrents and use more pieces to
    compensate.
  - Implement your own piece size calculation of arbitrary complexity by simply
    overloading Torrent.calculate_piece_size().


2019-04-04 2.0.0
  - Use proper version number scheme
  - Raise PieceSizeError if 'piece_size' is set to a number that isn't a power
    of two


2018-06-25 1.5
  - New methods read_stream() and write_stream() to import/export a torrent from
    any file-like object


2018-06-15 1.4
  - New method: calculate_piece_size()
  - Piece size is now automatically calculated when path is set instead of
    calculating it on demand when requested
  - Setting piece size to a non-number now raises ValueError instead of
    RuntimeError
  - Exclude patterns are now matched against every part of a file's path, not
    just the last part (i.e. the file name)
  - Setting torrent.path to '.' or '..' now sets the correct name
  - Torrent instances are equal (==) if their metainfo is equal
  - Torrent instances are hashable
  - Torrent instances can be copied with the copy() method or the copy module
    from the standard library


2018-04-07 1.3
  - Fix 'filepaths' attribute when setting a custom name


2018-02-19 1.2
  - Don't leave an empty file when calling write() on an invalid torrent


2018-02-18 1.1
  - 'announce' in metainfo is now a single URL instead of the first tier (Marcin
    Kurczewski)


2018-02-01 1.0
  - Nothing changed except that this is now the final 1.0 version


2018-01-13 1.0rc5
  - Fixed a bug where overwriting a torrent file resulted in corrupt torrent
  - Added property 'pieces' that returns the number of pieces
  - Added property 'filetree' that can be used to create a beautiful tree of a
    torrent's content
  - Added property 'is_ready' that is True when torrent can be exported
  - When reading torrent files, don't read large files all the way to EOF before
    failing
  - All exceptions now have an 'errno' attribute (see 'errno' module)


2018-01-03 1.0rc4
  - Torrent.write() and Torrent.read() take a file path instead of an opened
    file object
  - Some exception names have changed
  - Allow reading arbitrary bencoded data with validation turned off
  - Default 'created_by' value is now 'torf/<version>'


2017-12-27 1.0rc3
  - Reduce entropy with 'randomize_infohash' enabled (some parsers seem to have
    issues with large integers)


2017-12-25 1.0rc2
  - Add 'randomize_infohash' as a Torrent argument
  - Add 'name' as a Torrent argument
  - Call generate() callback again when all pieces are hashed
  - Validate 'metainfo' when accessing 'infohash' property


2017-12-21 1.0rc1
  Initial release
