Using a temporary file to keep the downloaded stream has the following advantages:
1- File is not saved to disk if it turns out it doesn't need to be saved (e.g. not rated)
2- If destination directory is a remote host (e.g. NFS share), then no unnecessary writes are made (i.e. if the file doesn't need to be saved).
things left to do:
fix tagging to also use the temporary file as opposed to the final audio file as source.
diff --git a/src/fly.c b/src/fly.c
index ea93929..1fb6de3 100644
--- a/src/fly.c
+++ b/src/fly.c
@@ -1122,47 +1122,80 @@ void BarFlyFinalize(void)
return;
}
-int BarFlyClose(BarFly_t* fly, BarSettings_t const* settings)
+int BarFlyCopyCompleted(BarFly_t* fly, BarSettings_t const* settings)
{
- int exit_status = 0;
- int status;
+ if (!fly) {
+ return 0;
+ }
- assert(settings != NULL);
+ fly->status = COPYING;
+ fseek(fly->temp_file, 0, SEEK_SET);
- if (fly != NULL) {
- /*
- * Close the file stream.
- */
- if (fly->audio_file != NULL) {
- fclose(fly->audio_file);
- }
+ /*
+ * Open a stream to the file.
+ */
+ int status = _BarFlyFileOpen(&fly->audio_file, fly->audio_file_path, settings);
- /*
- * Delete the file if it was not complete or not loved.
- */
- if (!fly->completed || (settings->downloadOnlyLoved && !fly->loved)) {
- fly->status = DELETING;
- status = _BarFlyFileDelete(fly, settings);
- if (status != 0) {
- exit_status = -1;
+ if (status == 0) {
+ char buf[BAR_FLY_COPY_BLOCK_SIZE];
+ memset(buf, 0, BAR_FLY_COPY_BLOCK_SIZE);
+ size_t s = 0, s2 = 0;
+
+ while (!feof(fly->temp_file)) {
+ s = fread(buf, 1, BAR_FLY_COPY_BLOCK_SIZE, fly->temp_file);
+
+ if (s != BAR_FLY_COPY_BLOCK_SIZE && !feof(fly->temp_file)) {
+ BarUiMsg(settings, MSG_INFO,
+ "Could not read temporary file (%d): %s\n",
+ errno,
+ strerror(errno));
+ break;
}
- }
- /*
- * Free the audio file name.
- */
- if (fly->audio_file_path != NULL) {
- free(fly->audio_file_path);
- }
+ s2 = fwrite(buf, 1, s, fly->audio_file);
- /*
- * Free the cover art URL.
- */
- if (fly->cover_art_url != NULL) {
- free(fly->cover_art_url);
+ if (s2 != s) {
+ BarUiMsg(settings, MSG_INFO,
+ "Could not write audio to destination %s (%d): %s\n",
+ fly->audio_file_path,
+ errno,
+ strerror(errno));
+ break;
+ }
}
}
+ fclose(fly->audio_file);
+}
+
+int BarFlyClose(BarFly_t* fly, BarSettings_t const* settings)
+{
+ if (!fly) {
+ return 0;
+ }
+
+ assert(settings != NULL);
+
+ int exit_status = 0;
+ int status;
+
+ /* closing the tmpfile() will delete it automatically */
+ fclose(fly->temp_file);
+
+ /*
+ * Free the audio file name.
+ */
+ if (fly->audio_file_path != NULL) {
+ free(fly->audio_file_path);
+ }
+
+ /*
+ * Free the cover art URL.
+ */
+ if (fly->cover_art_url != NULL) {
+ free(fly->cover_art_url);
+ }
+
return exit_status;
}
@@ -1347,22 +1380,17 @@ int BarFlyOpen(BarFly_t* fly, PianoSong_t const* song,
if (output_fly.audio_file_path == NULL) {
goto error;
}
-
+
/*
- * Open a stream to the file.
+ * Get a temporary file for download.
*/
- status = _BarFlyFileOpen(&output_fly.audio_file,
- output_fly.audio_file_path, settings);
- if (status == 0) {
- output_fly.status = RECORDING;
- } else if (status == -2) {
- output_fly.status = NOT_RECORDING_EXIST;
- output_fly.completed = true;
- } else {
- output_fly.completed = true;
+ output_fly.temp_file = tmpfile();
+ if (output_fly.temp_file == NULL) {
goto error;
}
+ output_fly.status = RECORDING;
+
/*
* All members of the BarFly_t structure were created successfully. Copy
* them from the temporary structure to the one passed in.
@@ -1420,6 +1448,10 @@ char const* BarFlyStatusGet(BarFly_t* fly)
string = "Deleting";
break;
+ case (COPYING):
+ string = "Copying";
+ break;
+
case (TAGGING):
string = "Tagging";
break;
@@ -1476,7 +1508,7 @@ int BarFlyWrite(BarFly_t* fly, void const* data, size_t data_size)
}
assert(fly->audio_file != NULL);
- status = fwrite(data, data_size, 1, fly->audio_file);
+ status = fwrite(data, data_size, 1, fly->temp_file);
if (status != 1) {
goto error;
}
diff --git a/src/fly.h b/src/fly.h
index e200512..e5551ac 100644
--- a/src/fly.h
+++ b/src/fly.h
@@ -52,6 +52,7 @@ typedef enum BarFlyStatus {
NOT_RECORDING_EXIST,
RECORDING,
DELETING,
+ COPYING,
TAGGING
} BarFlyStatus_t;
@@ -63,11 +64,16 @@ typedef enum BarFlyStatus {
*/
typedef struct BarFly {
/**
- * The stream to which the audio stream is written.
+ * The file to which the final audio stream is copied.
*/
FILE* audio_file;
/**
+ * The stream to which audio is written.
+ */
+ FILE* temp_file;
+
+ /**
* The audio file path.
*/
char* audio_file_path;
@@ -212,4 +218,13 @@ int BarFlyTag(BarFly_t* fly, BarSettings_t const* settings);
*/
int BarFlyWrite(BarFly_t* fly, void const* data, size_t data_size);
+/**
+ * Copies the temporary audio file to final destination
+ *
+ * @param fly Pointer to a BarFly_t structure.
+ * @param settings Pointer to the application settings structure.
+ * @return Upon success 0 is returned otherwise -1 is returned.
+ */
+int BarFlyCopyCompleted(BarFly_t* fly, BarSettings_t const* settings);
+
#endif /* _FLY_H */
diff --git a/src/player.c b/src/player.c
index 3c2cfdb..2ec35b1 100644
--- a/src/player.c
+++ b/src/player.c
@@ -518,8 +518,15 @@ void *BarPlayerThread (void *data) {
} while (wRet == WAITRESS_RET_PARTIAL_FILE || wRet == WAITRESS_RET_TIMEOUT
|| wRet == WAITRESS_RET_READ_ERR);
- /* If the song was played all the way through tag it. */
if (wRet == WAITRESS_RET_OK) {
+ if (!player->settings->downloadOnlyLoved ||
+ (player->settings->downloadOnlyLoved && !player->fly.loved)) {
+ BarUiMsg(player->settings, MSG_INFO, "Saving loved song.\n",
+ player->fly.audio_file_path);
+ BarFlyCopyCompleted(&player->fly, player->settings);
+ }
+
+ /* If the song was played all the way through tag it. */
BarFlyTag(&player->fly, player->settings);
}
Using a temporary file to keep the downloaded stream has the following advantages: 1- File is not saved to disk if it turns out it doesn't need to be saved (e.g. not rated) 2- If destination directory is a remote host (e.g. NFS share), then no unnecessary writes are made (i.e. if the file doesn't need to be saved).
things left to do: