3636namespace
3737{
3838 constexpr int HASH_TAG_HEX_LEN = 12 ;
39- constexpr int MAX_COMPONENT_LEN = 255 ;
4039
4140 PathList renameRootFolder (PathList filePaths, const QString &oldName, const QString &newName)
4241 {
@@ -52,24 +51,45 @@ namespace
5251 return filePaths;
5352 }
5453
55- // Sanitize and append tag, leaving room for the tag within MAX_COMPONENT_LEN.
56- QString hashedComponent (const QString &name, const QString &tag)
54+ // Same limits as Utils::Fs::isValidFileName (Win: 255 chars, else 255 UTF-8 bytes).
55+ bool exceedsFileNameLengthLimit (const QString &name)
56+ {
57+ #ifdef Q_OS_WIN
58+ return (name.length () > 255 );
59+ #else
60+ return (name.toUtf8 ().length () > 255 );
61+ #endif
62+ }
63+
64+ // Always keep full tag at the end; shorten the name until base+tag fits the platform limit.
65+ QString taggedComponent (const QString &name, const QString &tag)
5766 {
5867 QString base = Utils::Fs::toValidFileName (name.trimmed ());
5968 if (base.isEmpty ())
6069 base = u" Torrent" _s;
6170
6271 if (base.endsWith (tag))
63- return base;
72+ base. chop (tag. size ()) ;
6473
65- const int maxBaseLen = std::max (1 , MAX_COMPONENT_LEN - static_cast <int >(tag.size ()));
66- if (base.size () > maxBaseLen)
67- base = base.left (maxBaseLen);
74+ QString result = base + tag;
75+ while (exceedsFileNameLengthLimit (result) && !base.isEmpty ())
76+ {
77+ base.chop (1 );
78+ #ifdef Q_OS_WIN
79+ // Windows forbids trailing dots/spaces; tag starts with a space so keep base clean.
80+ while (base.endsWith (u' .' ) || base.endsWith (u' ' ))
81+ base.chop (1 );
82+ #endif
83+ result = base + tag;
84+ }
85+
86+ if (base.isEmpty ())
87+ result = u" Torrent" _s + tag;
6888
69- return base + tag ;
89+ return result ;
7090 }
7191
72- QString originalNameForHashDir (const PathList &filePaths, const QString &torrentName, const QString &tag)
92+ QString originalNameForUniqueDir (const PathList &filePaths, const QString &torrentName, const QString &tag)
7393 {
7494 QString base = torrentName.trimmed ();
7595 if (base.isEmpty ())
@@ -83,43 +103,41 @@ namespace
83103 if (base.isEmpty ())
84104 base = u" Torrent" _s;
85105
86- // Avoid "Name [qb-… ] [qb-…]" if the display/root name already carries this tag .
106+ // Avoid doubling the tag if the name already ends with it .
87107 if (base.endsWith (tag))
88108 base.chop (tag.size ());
89109
90110 return base;
91111 }
92112}
93113
94- QString BitTorrent::payloadHashTag (const TorrentID &id)
114+ QString BitTorrent::uniqueSubfolderTag (const TorrentID &id)
95115{
96- return u" [qb- " _s + id.toString ().left (HASH_TAG_HEX_LEN ) + u ' ] ' ;
116+ return u' ' + id.toString ().left (HASH_TAG_HEX_LEN );
97117}
98118
99- QString BitTorrent::payloadHashDirectoryName (const TorrentID &id, const QString &originalName)
119+ QString BitTorrent::uniqueSubfolderName (const TorrentID &id, const QString &originalName)
100120{
101- return hashedComponent (originalName, payloadHashTag (id));
121+ return taggedComponent (originalName, uniqueSubfolderTag (id));
102122}
103123
104- PathList BitTorrent::applyPayloadHashNaming (PathList filePaths, const TorrentID &id, const QString &torrentName)
124+ PathList BitTorrent::applyUniqueSubfolderLayout (PathList filePaths, const TorrentID &id, const QString &torrentName)
105125{
106126 if (filePaths.isEmpty ())
107127 return filePaths;
108128
109- const QString tag = payloadHashTag (id);
110- const QString hashDir = payloadHashDirectoryName (id, originalNameForHashDir (filePaths, torrentName, tag));
129+ const QString tag = uniqueSubfolderTag (id);
130+ const QString folderName = uniqueSubfolderName (id, originalNameForUniqueDir (filePaths, torrentName, tag));
111131
112132 const Path rootFolder = Path::findRootFolder (filePaths);
113133 if (!rootFolder.isEmpty ())
114134 {
115- // Already under the correct hash directory.
116- if (rootFolder.toString () == hashDir)
135+ if (rootFolder.toString () == folderName)
117136 return filePaths;
118- // Rename existing top-level folder (e.g. Show/ → Show [qb-HASH]/).
119- return renameRootFolder (std::move (filePaths), rootFolder.toString (), hashDir);
137+ return renameRootFolder (std::move (filePaths), rootFolder.toString (), folderName);
120138 }
121139
122- // Single file or rootless multi-file: wrap under the hash directory .
123- Path::addRootFolder (filePaths, Path (hashDir ));
140+ // Single file or rootless multi-file: wrap under the unique folder .
141+ Path::addRootFolder (filePaths, Path (folderName ));
124142 return filePaths;
125143}
0 commit comments