246 lines
7.2 KiB
C++
246 lines
7.2 KiB
C++
//An implement of CSCI-1200 HW1 Spotify Playlists
|
|
//Author: Jinshan Zhou
|
|
//Date: 2025/1/16
|
|
#include <vector>
|
|
#include <string>
|
|
#include <iostream>
|
|
#include <fstream>
|
|
//#include <algorithm>
|
|
//#include <sstream>
|
|
//#include <cmath>
|
|
//#include <cstdlib>
|
|
|
|
std::string get_text(const std::string &fname) {
|
|
//load a text file into a string
|
|
std::ifstream inFile(fname);
|
|
//check if file exists
|
|
if (!inFile) {
|
|
std::cout << "Error: File not found" << std::endl;
|
|
return "";
|
|
}
|
|
std::string text;
|
|
std::string line;
|
|
while (std::getline(inFile, line)) {
|
|
text += line;
|
|
text += "\n";
|
|
}
|
|
inFile.close();
|
|
|
|
return text;
|
|
}
|
|
|
|
std::vector<std::string> load_list(const std::string &fname) {
|
|
//load a text file into a vector of strings
|
|
std::string text = get_text(fname);
|
|
|
|
std::vector<std::string> lines;
|
|
std::size_t start = 0;
|
|
std::size_t end = 0;
|
|
while ((end = text.find('\n', start)) != std::string::npos) {
|
|
lines.push_back(text.substr(start, end - start));
|
|
start = end + 1;
|
|
}
|
|
if (start < text.size()) {
|
|
lines.push_back(text.substr(start));
|
|
}
|
|
|
|
return lines;
|
|
}
|
|
|
|
void debug_print(const std::string &msg) {
|
|
std::cout << "DEBUG: " << msg << std::endl;
|
|
}
|
|
|
|
bool is_all_digits(const std::string& s) {
|
|
//check if string is int
|
|
for (char c : s) {
|
|
if (!std::isdigit(static_cast<unsigned char>(c))) {
|
|
return false;
|
|
}
|
|
}
|
|
return !s.empty();
|
|
}
|
|
|
|
std::vector<std::string> tokenizer(const std::string &s) {
|
|
//split string into tokens
|
|
std::vector<std::string> tokens;
|
|
std::string token;
|
|
for (char c : s) {
|
|
if (c == ' ') {
|
|
tokens.push_back(token);
|
|
token = "";
|
|
} else {
|
|
token += c;
|
|
}
|
|
}
|
|
tokens.push_back(token);
|
|
return tokens;
|
|
}
|
|
|
|
bool check_in_list (const std::string &s, const std::vector<std::string> &list) {
|
|
//check if string is in list
|
|
for (std::string item : list) {
|
|
if (s == item) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void remove_in_list (const std::string &s, std::vector<std::string> &list) {
|
|
//remove string from list
|
|
if (!check_in_list(s, list)) {return;}
|
|
for (int i = 0; i < list.size(); i++) {
|
|
if (list[i] == s) {
|
|
list.erase(list.begin() + i);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
int get_current (std::vector<std::string> &playlist) {
|
|
//return the index of the string has word current at the end
|
|
for (int i = 0; i < playlist.size(); i++) {
|
|
if (playlist[i].find("current") != std::string::npos) {
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
std::string build_song (const std::vector<std::string> &tokens, const int &start, const int &end) {
|
|
//build string from tokens w/ start and end positions
|
|
std::string song;
|
|
for (int i = start; i < end; i++) {
|
|
song += tokens[i];
|
|
if (i != end - 1) {
|
|
song += " ";
|
|
}
|
|
}
|
|
return song;
|
|
}
|
|
|
|
void write_list(const std::string &fname, const std::vector<std::string> &list) {
|
|
//write list to file
|
|
std::ofstream outFile(fname);
|
|
for (std::string line : list) {
|
|
outFile << line << std::endl;
|
|
}
|
|
outFile.close();
|
|
}
|
|
|
|
int main(int argc, char *argv[]) {
|
|
//take 3 arguments
|
|
if (argc < 3) {
|
|
std::cout << "Error: Not enough arguments" << std::endl;
|
|
return 1;
|
|
}
|
|
//load arguments
|
|
std::string playlist_fname = argv[1];
|
|
std::string action_list_fname = argv[2];
|
|
std::string output_fname = argv[3];
|
|
//turn on debug mode is last argument is debug
|
|
bool debug_mode = false;
|
|
if (std::string(argv[argc - 1]) == "debug") {
|
|
debug_mode = true;
|
|
}
|
|
|
|
if (debug_mode) {
|
|
debug_print("playlist_fname =" + playlist_fname);
|
|
debug_print("action_list_fname =" + action_list_fname);
|
|
debug_print("output_fname =" + output_fname);
|
|
}
|
|
//load working files
|
|
std::vector<std::string> playlist = load_list(playlist_fname);
|
|
std::vector<std::string> action_list = load_list(action_list_fname);
|
|
//get current playing song id
|
|
int current_song_id = get_current(playlist);
|
|
if (debug_mode) {
|
|
debug_print("current_song_id = " + std::to_string(current_song_id));
|
|
}
|
|
//execute actions
|
|
for (std::string command : action_list) {
|
|
if (debug_mode) {
|
|
debug_print("Command = " + command);
|
|
}
|
|
//split command into tokens
|
|
std::vector<std::string> tokens = tokenizer(command);
|
|
if (tokens[0] == "next") {
|
|
current_song_id = get_current(playlist);
|
|
//remove "current" tag
|
|
playlist[current_song_id].erase(playlist[current_song_id].length() - 8);
|
|
if (current_song_id == playlist.size() - 1) {
|
|
current_song_id = 0;
|
|
} else {
|
|
current_song_id++;
|
|
}
|
|
//update current song
|
|
playlist[current_song_id] += " current";
|
|
}
|
|
if (tokens[0] == "previous") {
|
|
current_song_id = get_current(playlist);
|
|
//remove "current" tag
|
|
playlist[current_song_id].erase(playlist[current_song_id].length() - 8);
|
|
if (current_song_id == 0) {
|
|
current_song_id = playlist.size() - 1;
|
|
} else {
|
|
current_song_id--;
|
|
}
|
|
//update current song
|
|
playlist[current_song_id] += " current";
|
|
}
|
|
if (tokens[0] == "add") {
|
|
std::string song;
|
|
song = build_song(tokens, 1, tokens.size());
|
|
playlist.push_back(song);
|
|
|
|
if (debug_mode) {
|
|
debug_print("Added = " + song);
|
|
}
|
|
}
|
|
if (tokens[0] == "remove") {
|
|
std::string song;
|
|
song = build_song(tokens, 1, tokens.size());
|
|
remove_in_list(song, playlist);
|
|
|
|
if (debug_mode) {
|
|
debug_print("Removed = " + song);
|
|
}
|
|
}
|
|
if (tokens[0] == "move") {
|
|
if (is_all_digits(tokens.back())){
|
|
//set target position
|
|
int dest = std::stoi(tokens.back());
|
|
//build song from tokens
|
|
std::string song;
|
|
song = build_song(tokens, 1, tokens.size() - 1);
|
|
//fix song name if it has current tag
|
|
if (!check_in_list(song, playlist) &&
|
|
!check_in_list(song + " current", playlist)) {continue;}
|
|
else if (check_in_list(song + " current", playlist)) {
|
|
song += " current";
|
|
}
|
|
remove_in_list(song, playlist);
|
|
playlist.insert(playlist.begin() + dest - 1, song);
|
|
|
|
if (debug_mode) {
|
|
debug_print("Moved " + song + " to " + std::to_string(dest));
|
|
}
|
|
} else {
|
|
std::cout << "ERROR: Missing move destination" << std::endl;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
}
|
|
//write back file
|
|
write_list(output_fname, playlist);
|
|
|
|
if (debug_mode) {
|
|
debug_print("Playlist Content:");
|
|
for (std::string line : playlist) {
|
|
std::cout << line << std::endl;
|
|
}
|
|
}
|
|
return 0;
|
|
} |