1 /* 2 * Copyright 2003-2021 The Music Player Daemon Project 3 * http://www.musicpd.org 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License along 16 * with this program; if not, write to the Free Software Foundation, Inc., 17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 */ 19 20 #ifndef MPD_DETACHED_SONG_HXX 21 #define MPD_DETACHED_SONG_HXX 22 23 #include "tag/Tag.hxx" 24 #include "pcm/AudioFormat.hxx" 25 #include "Chrono.hxx" 26 27 #include <chrono> 28 #include <string> 29 #include <utility> 30 31 struct LightSong; 32 class Storage; 33 class Path; 34 35 class DetachedSong { 36 friend DetachedSong DatabaseDetachSong(const Storage &db, 37 const LightSong &song); 38 39 /** 40 * An UTF-8-encoded URI referring to the song file. This can 41 * be one of: 42 * 43 * - an absolute URL with a scheme 44 * (e.g. "http://example.com/foo.mp3") 45 * 46 * - an absolute file name 47 * 48 * - a file name relative to the music directory 49 */ 50 std::string uri; 51 52 /** 53 * The "real" URI, the one to be used for opening the 54 * resource. If this attribute is empty, then #uri shall be 55 * used. 56 * 57 * This attribute is used for songs from the database which 58 * have a relative URI. 59 */ 60 std::string real_uri; 61 62 Tag tag; 63 64 /** 65 * The time stamp of the last file modification. A negative 66 * value means that this is unknown/unavailable. 67 */ 68 std::chrono::system_clock::time_point mtime = 69 std::chrono::system_clock::time_point::min(); 70 71 /** 72 * Start of this sub-song within the file. 73 */ 74 SongTime start_time = SongTime::zero(); 75 76 /** 77 * End of this sub-song within the file. 78 * Unused if zero. 79 */ 80 SongTime end_time = SongTime::zero(); 81 82 /** 83 * The audio format of the song, if given by the decoder 84 * plugin. May be undefined if unknown. 85 */ 86 AudioFormat audio_format = AudioFormat::Undefined(); 87 88 public: DetachedSong(const char * _uri)89 explicit DetachedSong(const char *_uri) noexcept 90 :uri(_uri) {} 91 DetachedSong(const std::string & _uri)92 explicit DetachedSong(const std::string &_uri) noexcept 93 :uri(_uri) {} 94 DetachedSong(std::string && _uri)95 explicit DetachedSong(std::string &&_uri) noexcept 96 :uri(std::move(_uri)) {} 97 98 template<typename U> DetachedSong(U && _uri,Tag && _tag)99 DetachedSong(U &&_uri, Tag &&_tag) noexcept 100 :uri(std::forward<U>(_uri)), 101 tag(std::move(_tag)) {} 102 103 /** 104 * Copy data from a #LightSong instance. Usually, you should 105 * call DatabaseDetachSong() instead, which initializes 106 * #real_uri properly using Storage::MapUTF8(). 107 */ 108 explicit DetachedSong(const LightSong &other) noexcept; 109 110 ~DetachedSong() noexcept = default; 111 112 /* these are declared because the user-defined destructor 113 above prevents them from being generated implicitly */ 114 explicit DetachedSong(const DetachedSong &) = default; 115 DetachedSong(DetachedSong &&) = default; 116 DetachedSong &operator=(DetachedSong &&) = default; 117 118 [[gnu::pure]] 119 explicit operator LightSong() const noexcept; 120 121 [[gnu::pure]] GetURI() const122 const char *GetURI() const noexcept { 123 return uri.c_str(); 124 } 125 126 template<typename T> SetURI(T && _uri)127 void SetURI(T &&_uri) noexcept { 128 uri = std::forward<T>(_uri); 129 } 130 131 /** 132 * Does this object have a "real" URI different from the 133 * displayed URI? 134 */ 135 [[gnu::pure]] HasRealURI() const136 bool HasRealURI() const noexcept { 137 return !real_uri.empty(); 138 } 139 140 /** 141 * Returns "real" URI (#real_uri) and falls back to just 142 * GetURI(). 143 */ 144 [[gnu::pure]] GetRealURI() const145 const char *GetRealURI() const noexcept { 146 return (HasRealURI() ? real_uri : uri).c_str(); 147 } 148 149 template<typename T> SetRealURI(T && _uri)150 void SetRealURI(T &&_uri) noexcept { 151 real_uri = std::forward<T>(_uri); 152 } 153 154 /** 155 * Returns true if both objects refer to the same physical 156 * song. 157 */ 158 [[gnu::pure]] IsSame(const DetachedSong & other) const159 bool IsSame(const DetachedSong &other) const noexcept { 160 return uri == other.uri && 161 start_time == other.start_time && 162 end_time == other.end_time; 163 } 164 165 [[gnu::pure]] [[gnu::nonnull]] IsURI(const char * other_uri) const166 bool IsURI(const char *other_uri) const noexcept { 167 return uri == other_uri; 168 } 169 170 [[gnu::pure]] [[gnu::nonnull]] IsRealURI(const char * other_uri) const171 bool IsRealURI(const char *other_uri) const noexcept { 172 return (HasRealURI() ? real_uri : uri) == other_uri; 173 } 174 175 [[gnu::pure]] 176 bool IsRemote() const noexcept; 177 178 [[gnu::pure]] IsFile() const179 bool IsFile() const noexcept { 180 return !IsRemote(); 181 } 182 183 [[gnu::pure]] 184 bool IsAbsoluteFile() const noexcept; 185 186 [[gnu::pure]] 187 bool IsInDatabase() const noexcept; 188 GetTag() const189 const Tag &GetTag() const noexcept { 190 return tag; 191 } 192 WritableTag()193 Tag &WritableTag() noexcept { 194 return tag; 195 } 196 SetTag(const Tag & _tag)197 void SetTag(const Tag &_tag) noexcept { 198 tag = Tag(_tag); 199 } 200 SetTag(Tag && _tag)201 void SetTag(Tag &&_tag) noexcept { 202 tag = std::move(_tag); 203 } 204 MoveTagFrom(DetachedSong && other)205 void MoveTagFrom(DetachedSong &&other) noexcept { 206 tag = std::move(other.tag); 207 } 208 209 /** 210 * Similar to the MoveTagFrom(), but move only the #TagItem 211 * array. 212 */ MoveTagItemsFrom(DetachedSong && other)213 void MoveTagItemsFrom(DetachedSong &&other) noexcept { 214 tag.MoveItemsFrom(std::move(other.tag)); 215 } 216 GetLastModified() const217 std::chrono::system_clock::time_point GetLastModified() const noexcept { 218 return mtime; 219 } 220 SetLastModified(std::chrono::system_clock::time_point _value)221 void SetLastModified(std::chrono::system_clock::time_point _value) noexcept { 222 mtime = _value; 223 } 224 GetStartTime() const225 SongTime GetStartTime() const noexcept { 226 return start_time; 227 } 228 SetStartTime(SongTime _value)229 void SetStartTime(SongTime _value) noexcept { 230 start_time = _value; 231 } 232 GetEndTime() const233 SongTime GetEndTime() const noexcept { 234 return end_time; 235 } 236 SetEndTime(SongTime _value)237 void SetEndTime(SongTime _value) noexcept { 238 end_time = _value; 239 } 240 241 [[gnu::pure]] 242 SignedSongTime GetDuration() const noexcept; 243 GetAudioFormat() const244 const AudioFormat &GetAudioFormat() const noexcept { 245 return audio_format; 246 } 247 SetAudioFormat(const AudioFormat & src)248 void SetAudioFormat(const AudioFormat &src) noexcept { 249 audio_format = src; 250 } 251 252 /** 253 * Update the #tag and #mtime. 254 * 255 * Throws on error. 256 * 257 * @return true on success 258 */ 259 bool Update(); 260 261 /** 262 * Load #tag and #mtime from a local file. 263 * 264 * Throws on error. 265 */ 266 bool LoadFile(Path path); 267 }; 268 269 #endif 270