diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1949def --- /dev/null +++ b/Makefile @@ -0,0 +1,19 @@ +## +# radio_plus_plus +# +# @MakeFile +# @version 0.1 + +all: compile install config + +compile: + g++ --verbose -o radio *.cpp *.h `wx-config --cxxflags --libs` -lvlc -lcurl -ljsoncpp -fgcse-after-reload -fipa-cp-clone -floop-interchange -floop-unroll-and-jam -fpeel-loops -fpredictive-commoning -fsplit-loops -fsplit-paths -ftree-loop-distribution -ftree-partial-pre -funswitch-loops -fvect-cost-model=dynamic -fversion-loops-for-strides + +install: + cp -v radio /usr/local/bin + +config: + mkdir -p ~/.config/radio++ + touch ~/.config/radio++/sender + +# end diff --git a/README.md b/README.md index ad6b9eb..aba7ff0 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,29 @@ -# radio_plus_plus +# Radio ++ +### Dependencies +> g++ \ +> wxgtk3 \ +> vlc \ +> curl \ +> jsoncpp -A cool c++ Internet Radio Player \ No newline at end of file +### Arch +``` +sudo pacman -S gcc wxgtk3 vlc curl jsoncpp +``` + +### Debian/Ubuntu +``` +sudo apt-get install g++ libwxgtk3.0-dev libvlc-dev libcurl-dev libjsoncpp-dev +``` + +### Gentoo GNU/Linux +``` +doas emerge -aq jsoncpp vlc x11-libs/wxGTK-3.0 +``` + +### Installing +``` +git clone https://github.com/MIROowo/radio_plus_plus.git +cd radio_plus_plus +sh compile.sh +``` diff --git a/compile.sh b/compile.sh new file mode 100644 index 0000000..a0b4046 --- /dev/null +++ b/compile.sh @@ -0,0 +1,19 @@ +g++ -o radio *.cpp *.h `wx-config --cxxflags --libs` -lvlc -lcurl -ljsoncpp + +if [ -x ./radio ] +then + read -p "Do u want to install the Binary? [y/N] " input + + if [ $input = "y" ] || [ $input = "Y" ] + then + mkdir -p ~/.config/radio++/ + touch ~/.config/radio++/sender + doas cp -v radio /usr/local/bin/ + echo "Finished!" + else + echo "bye :c" + fi +else + echo "something went wrong :/" + echo "exit..." +fi diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..9add622 --- /dev/null +++ b/main.cpp @@ -0,0 +1,220 @@ +#include "main.h" +#include "search.h" + +// Binding events to functions +wxBEGIN_EVENT_TABLE(cFrame, wxFrame) + EVT_BUTTON(1001, cFrame::OnPP) + EVT_SLIDER(1002, cFrame::OnScroll) + EVT_BUTTON(1003, cFrame::OnAdd) + EVT_BUTTON(1004, cFrame::OnRemove) + EVT_BUTTON(1005, cFrame::OnSearch) + EVT_BUTTON(1008, cFrame::refreshEvent) +wxEND_EVENT_TABLE() + +// Window content +cFrame::cFrame() : wxFrame(nullptr, wxID_ANY, "Radio++", wxPoint(30, 30), wxSize(450, 600)) { + + wxFrame::SetMinSize(wxSize(450, 600)); + wxFrame::SetMaxSize(wxSize(450, 600)); + + menuBar->Append(menuHelp, "&Help"); + menuHelp->Append(wxID_ABOUT); + menuHelp->AppendSeparator(); + menuHelp->Append(wxID_EXIT); + + SetMenuBar(menuBar); + + Bind(wxEVT_MENU, &cFrame::OnAbout, this, wxID_ABOUT); + Bind(wxEVT_MENU, &cFrame::OnExit, this, wxID_EXIT); + + b_pp = new wxButton(this, 1001, "Play", wxPoint(10, 10), wxSize(100,50)); + t_box = new wxTextCtrl(this, wxID_ANY, "", wxPoint(10, 190), wxSize(250, 30)); + t_show = new wxStaticText(this, wxID_ANY, "None", wxPoint(10, 80), wxSize(50, 100)); + s_val = new wxStaticText(this, wxID_ANY, "70", wxPoint(150, 100), wxSize(50, 100)); + s_volume = new wxSlider(this, 1002, 70, 0, 100, wxPoint(50, 100), wxSize(220, 80)); + + b_add = new wxButton(this, 1003, "Add", wxPoint(280, 230), wxSize(80,30)); + b_add = new wxButton(this, 1004, "Remove", wxPoint(280, 270), wxSize(80,30)); + s_sender = new wxButton(this, 1005, "Search", wxPoint(280, 310), wxSize(80,30)); + b_refresh = new wxButton(this, 1008, "Refresh", wxPoint(280, 350), wxSize(80,30)); + l_sender = new wxListBox(this, wxID_ANY, wxPoint(10, 230), wxSize(250, 300)); + + // Text for the Statusbar + CreateStatusBar(); + SetStatusText("Radio++"); + + cFrame::refreshList(); +} + +cFrame::~cFrame() { +} + +void cFrame::refreshList() { + + l_sender->Clear(); + + readfile.open(homedir+"/.config/radio++/sender"); + + if (readfile.is_open()) + { + while ( getline (readfile,line) ) + { + wxString wx_line(line); + l_sender->Append(wx_line); + } + + readfile.close(); + + } + +} + +void cFrame::refreshEvent(wxCommandEvent &evt) { + + l_sender->Clear(); + + readfile.open(homedir+"/.config/radio++/sender"); + + if (readfile.is_open()) + { + while ( getline (readfile,line) ) + { + wxString wx_line(line); + l_sender->Append(wx_line); + } + + readfile.close(); + + } + evt.Skip(); +} + +// Get Slider Value and sets Volume +void cFrame::OnScroll(wxCommandEvent &evt) { + + wxString value = wxString::Format(wxT("%d"), (int)s_volume->GetValue()); + + s_val->SetLabel(value); + int vol = wxAtoi(value); + if (b_pp->GetLabel() == "Pause") { + libvlc_audio_set_volume(mp, vol); + } + evt.Skip(); +} + +// Plays Radio sound yee +void cFrame::playRadio(const char* url) { + + sender = libvlc_media_new_location(inst, url); + mp = libvlc_media_player_new_from_media(sender); + libvlc_media_player_play(mp); +} + + +// Play/Pause Button +void cFrame::OnPP(wxCommandEvent &evt) { + + if(b_pp->GetLabel() == "Play") { + + t_show->SetLabel("Playing..."); + b_pp->SetLabel("Pause"); + + std::string url = std::string(l_sender->GetStringSelection().mb_str()); + const char * c_url = url.c_str(); + + cFrame::playRadio(c_url); + + wxString value = s_val->GetLabel(); + int vol = wxAtoi(value); + libvlc_audio_set_volume(mp, vol); + + } else if (b_pp->GetLabel() == "Pause") { + + t_show->SetLabel("Paused"); + b_pp->SetLabel("Play"); + + libvlc_media_player_stop(mp); + } + + evt.Skip(); + + } +// Add Button +void cFrame::OnAdd(wxCommandEvent &evt) { + l_sender->Append(t_box->GetValue()); + + std::string item = std::string(t_box->GetValue().mb_str()); + + writefile.open(homedir+"/.config/radio++/sender", std::ios::app); + writefile << item << "\n"; + + writefile.close(); + + t_box->Clear(); +} + +// Remove Button +void cFrame::OnRemove(wxCommandEvent &evt) { + + if (l_sender->GetSelection() != wxNOT_FOUND) { + + std::string deleteline = std::string(l_sender->GetStringSelection().mb_str()); + + l_sender->Delete(l_sender->GetSelection()); + + // https://stackoverflow.com/questions/26576714/deleting-specific-line-from-file + + std::string path = homedir+"/.config/radio++/sender"; + std::string tempfile = homedir+"/.config/radio++/temp.txt"; + std::string line; + std::ifstream fin; + + fin.open(path); + // contents of path must be copied to a temp file then + // renamed back to the path file + std::ofstream temp; + temp.open(homedir+"/.config/radio++/temp.txt"); + + while (getline(fin, line)) { + // write all lines to temp other than the line marked for erasing + if (line != deleteline) + temp << line << std::endl; + } + + temp.close(); + fin.close(); + + // required conversion for remove and rename functions + const char * t = tempfile.c_str(); + const char * p = path.c_str(); + remove(p); + rename(t, p); + } + + evt.Skip(); + +} + +// Search Button +void cFrame::OnSearch(wxCommandEvent &evt) +{ + cSearch* m_frame2 = new cSearch(); + m_frame2->Show(true); + evt.Skip(); + + +} + + +// OnAbout +void cFrame::OnAbout(wxCommandEvent &evt) +{ + wxMessageBox("By MIRO#5825", + "About", wxOK | wxICON_INFORMATION); +} + +// OnExit +void cFrame::OnExit(wxCommandEvent &evt) { + libvlc_release (inst); + Close(true); +} \ No newline at end of file diff --git a/main.h b/main.h new file mode 100644 index 0000000..164f139 --- /dev/null +++ b/main.h @@ -0,0 +1,72 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + + +class cFrame : public wxFrame { + public: + cFrame(); + ~cFrame(); + + struct passwd *pw = getpwuid(getuid()); + std::string homedir = pw->pw_dir; + + // Window content declaration + + libvlc_media_player_t *mp; + libvlc_media_t *sender; + + libvlc_instance_t * inst = libvlc_new (0, NULL); + + wxMenuBar *menuBar = new wxMenuBar; + wxMenu *menuHelp = new wxMenu; + + wxTextCtrl *t_box = nullptr; + wxStaticText *t_show = nullptr; + + wxListBox *l_sender = nullptr; + + wxButton *b_pp = nullptr; + wxButton *b_add = nullptr; + wxButton *s_sender = nullptr; + wxButton *b_refresh = nullptr; + + wxStaticText *s_val = nullptr; + wxSlider *s_volume = nullptr; + + std::ifstream readfile; + std::ofstream writefile; + + std::string line; + + void refreshList(); + + void refreshEvent(wxCommandEvent &evt); + + void eraseFileLine(std::string path, std::string eraseLine); + + void OnScroll(wxCommandEvent &evt); + + void playRadio(const char* url); + + void OnPP(wxCommandEvent &evt); + + void OnAbout(wxCommandEvent &evt); + + void OnExit(wxCommandEvent &evt); + + void OnAdd(wxCommandEvent &evt); + + void OnRemove(wxCommandEvent &evt); + + void OnSearch(wxCommandEvent &evt); + + wxDECLARE_EVENT_TABLE(); + +}; \ No newline at end of file diff --git a/search.cpp b/search.cpp new file mode 100644 index 0000000..2cd4a21 --- /dev/null +++ b/search.cpp @@ -0,0 +1,95 @@ +#include "search.h" + +wxBEGIN_EVENT_TABLE(cSearch, wxFrame) + EVT_BUTTON(1006, cSearch::onSearch) + EVT_BUTTON(1007, cSearch::onAdd) +wxEND_EVENT_TABLE() + +cSearch::cSearch() : wxFrame(nullptr, wxID_ANY, "Search", wxPoint(30, 30), wxSize(500, 700)) +{ + wxFrame::SetMinSize(wxSize(500, 700)); + wxFrame::SetMaxSize(wxSize(500, 700)); + + searchBox = new wxTextCtrl(this, wxID_ANY, "", wxPoint(10, 20), wxSize(300, 40)); + searchButton = new wxButton(this, 1006, "Search", wxPoint(365, 20), wxSize(80, 40)); + searchAdd = new wxButton(this, 1007, "Add", wxPoint(365, 70), wxSize(80, 40)); + searchList = new wxListBox(this, wxID_ANY, wxPoint(10, 130), wxSize(480, 500)); + +} + +cSearch::~cSearch() +{ + +} + +static size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp) +{ + ((std::string*)userp)->append((char*)contents, size * nmemb); + return size * nmemb; +} + + +void cSearch::onSearch(wxCommandEvent &evt) { + + searchList->Clear(); + + wxString boxValue(searchBox->GetValue()); + std::string api = "https://api.laut.fm/search/stations?query=" + std::string(boxValue.mb_str()); + + CURL *curl; + CURLcode res; + std::string readBuffer; + + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, api.c_str()); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + + bool j_parse = jread.parse(readBuffer, jval, false); + + if (j_parse) { + + Json::Value arrays = jval["results"][0]["items"]; + + int arraynum = arrays.size(); + + + for (int i = 0; i < arraynum; i++) + { + std::string name = fastWriter.write(jval["results"][0]["items"][i]["station"]["stream_url"]); + searchList->Append(name); + } + } + } + evt.Skip(); +} + +void cSearch::onAdd(wxCommandEvent &evt) +{ + if (searchList->GetSelection() != wxNOT_FOUND) + { + std::string item = std::string(searchList->GetStringSelection()); + + item.erase(0, 1); + + int start{item.length()-2}; + int end{item.length()-1}; + + item.erase(start, end); + + std::ofstream writefile; + + writefile.open(homedir+"/.config/radio++/sender", std::ios::app); + writefile << item << "\n"; + writefile.close(); + + + } + + evt.Skip(); +} + + diff --git a/search.h b/search.h new file mode 100644 index 0000000..6fdf36b --- /dev/null +++ b/search.h @@ -0,0 +1,31 @@ +#include +#include +#include +#include + +#include "main.h" + +class cSearch : public wxFrame { + public: + cSearch(); + ~cSearch(); + + struct passwd *pw = getpwuid(getuid()); + std::string homedir = pw->pw_dir; + + Json::FastWriter fastWriter; + Json::Reader jread; + Json::Value jval; + + wxTextCtrl *searchBox = nullptr; + wxButton *searchButton = nullptr; + wxButton *searchAdd =nullptr; + + wxListBox *searchList = nullptr; + + void onSearch(wxCommandEvent &evt); + + void onAdd(wxCommandEvent &evt); + + wxDECLARE_EVENT_TABLE(); +}; \ No newline at end of file diff --git a/update.sh b/update.sh new file mode 100644 index 0000000..4a2f14b --- /dev/null +++ b/update.sh @@ -0,0 +1,2 @@ +#!/usr/bin/sh +git pull origin master diff --git a/window.cpp b/window.cpp new file mode 100644 index 0000000..46e90ff --- /dev/null +++ b/window.cpp @@ -0,0 +1,23 @@ +#include "window.h" +#include "main.h" + +wxIMPLEMENT_APP(cWindow); + +cWindow::cWindow() { + +} + +cWindow::~cWindow() { + +} + +// GUI Init +bool cWindow::OnInit() { + + m_frame1 = new cFrame(); + m_frame1->Show(true); + + return true; + +} + diff --git a/window.h b/window.h new file mode 100644 index 0000000..0539776 --- /dev/null +++ b/window.h @@ -0,0 +1,16 @@ +#pragma once + +#include "main.h" +#include + +class cWindow : public wxApp { + public: + cWindow(); + ~cWindow(); + + private: + cFrame* m_frame1 = nullptr; + + public: + virtual bool OnInit(); +}; \ No newline at end of file