From e14f41854981430767ecb50752facb2528a783fd Mon Sep 17 00:00:00 2001 From: Jack Merrill Date: Wed, 5 Mar 2025 23:48:23 -0500 Subject: [PATCH] :tada: init --- .cache | 1 + .conda/conda-meta/history | 3 + .conda/etc/aau_token | 1 + .env | 13 ++ .vscode/settings.json | 26 +++ interactive/__init__.py | 71 +++++++ .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 4056 bytes interactive/__pycache__/app.cpython-312.pyc | Bin 0 -> 652 bytes interactive/app.tcss | 14 ++ main.py | 179 ++++++++++++++++++ setup.py | 15 ++ 11 files changed, 323 insertions(+) create mode 100644 .cache create mode 100644 .conda/conda-meta/history create mode 100644 .conda/etc/aau_token create mode 100644 .env create mode 100644 .vscode/settings.json create mode 100644 interactive/__init__.py create mode 100644 interactive/__pycache__/__init__.cpython-312.pyc create mode 100644 interactive/__pycache__/app.cpython-312.pyc create mode 100644 interactive/app.tcss create mode 100644 main.py create mode 100644 setup.py diff --git a/.cache b/.cache new file mode 100644 index 0000000..4361702 --- /dev/null +++ b/.cache @@ -0,0 +1 @@ +{"access_token": "BQBWXQ1ckGLrSfA-YY-2lNfuOkd3wifoGFgGLeLBUIzBpA8GYxXNTZnHjh3z3uUoQz-wyuWSQl0rpokmlJxsOPOfgv6jY4NDX_sM0n7CLUizpSCI4yTZVrDhp22pEdeCpp9OyM3awmdyc7I8wmjjELV5l-ipU1JHUyyOAmM9pZMsJaCk70yaJkLOM5VJbWK-1BGcpBrHP61g5xYsuuXFKY3qtq7ZXJyKUOXDuRNf_MZOu2_F9sKM6jARYRAD2d2OQVGqmnqcoWDIzTwrZtZMuQLA6WwabQd8Uq5ZSn4QYJery_GUq_58FipuSk_GsbPuVp1maOfMr4CP6o9AZH2US-w99SC4xljEsqqiNw", "token_type": "Bearer", "expires_in": 3600, "scope": "playlist-modify-private playlist-modify-public playlist-read-collaborative playlist-read-private user-library-read", "expires_at": 1741215249, "refresh_token": "AQCQ_aGEnBpVKH9nMJfWKV7c61kUubyy-Ki3ppUsgqom1LnbPobUjBDsrtMQJ49_VZ6zG-edqKJL41418B_IcUIRAvRgMkN5Qr58P4UHSAxLhShyDRfAHkSw07nr8q70WLQ"} \ No newline at end of file diff --git a/.conda/conda-meta/history b/.conda/conda-meta/history new file mode 100644 index 0000000..e787f9a --- /dev/null +++ b/.conda/conda-meta/history @@ -0,0 +1,3 @@ +==> 2025-03-04 17:43:37 <== +# cmd: /opt/miniconda3/bin/conda create -p ./.conda +# conda version: 24.7.1 diff --git a/.conda/etc/aau_token b/.conda/etc/aau_token new file mode 100644 index 0000000..cb1dd8c --- /dev/null +++ b/.conda/etc/aau_token @@ -0,0 +1 @@ +2QifZUSOTs8qIPOH81Obaw \ No newline at end of file diff --git a/.env b/.env new file mode 100644 index 0000000..ad2fb03 --- /dev/null +++ b/.env @@ -0,0 +1,13 @@ +SPOTIFY_CLIENT_ID=dfc2029a49574c2abc752adf4ba96756 +SPOTIFY_CLIENT_SECRET=c31d0ed2991040a1bc010be012f5f1b9 +SUBSONIC_BASE_URL=http://192.168.1.201 +SUBSONIC_PORT=4533 +SUBSONIC_USERNAME=jack +SUBSONIC_PASSWORD=Chrome1738! +SPOTIFY_REDIRECT_URI=http://127.0.0.1:8888/callback +DEEZER_ARL= +YOUTUBE_REQUEST_HEADERS= + +LIDARR_API_KEY=11c8fa0adc3e486eb14613d39c4f8ede +LIDARR_BASE_URL=http://192.168.1.167:8686 +LIDARR_ROOT_DIR=/data/Music diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..edacb81 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,26 @@ +{ + "python.languageServer": "Pylance", + "python.analysis.diagnosticSeverityOverrides": { + "reportMissingModuleSource": "none", + "reportShadowedImports": "none" + }, + "python.analysis.extraPaths": [ + "c:\\Users\\me\\.vscode\\extensions\\continue.continue-0.0.412-win32-x64", + "/home/jack/.vscode/extensions/joedevivo.vscode-circuitpython-0.2.0-linux-x64/stubs", + "/home/jack/.config/Code/User/globalStorage/joedevivo.vscode-circuitpython/bundle/20250305/adafruit-circuitpython-bundle-py-20250305/lib", + "/Users/jack/.vscode/extensions/continue.continue-0.1.40-darwin-arm64", + "/Users/jack/.vscode/extensions/continue.continue-0.2.0-darwin-arm64", + "/Users/jack/.vscode/extensions/continue.continue-0.5.0-darwin-arm64", + "/Users/jack/.vscode/extensions/continue.continue-0.6.0-darwin-arm64", + "/Users/jack/.vscode/extensions/continue.continue-0.6.2-darwin-arm64", + "/Users/jack/.vscode/extensions/continue.continue-0.6.3-darwin-arm64", + "/Users/jack/.vscode/extensions/continue.continue-0.6.8-darwin-arm64", + "/Users/jack/.vscode/extensions/continue.continue-0.6.13-darwin-arm64", + "/Users/jack/.vscode/extensions/continue.continue-0.6.15-darwin-arm64", + "c:\\Users\\yoshi\\.vscode\\extensions\\continue.continue-0.6.15-win32-x64", + "c:\\Users\\yoshi\\.vscode\\extensions\\continue.continue-0.6.18-win32-x64", + "c:\\Users\\yoshi\\.vscode\\extensions\\continue.continue-0.8.0-win32-x64", + "c:\\Users\\yoshi\\.vscode\\extensions\\continue.continue-0.8.1-win32-x64" + ], + "circuitpython.board.version": null +} \ No newline at end of file diff --git a/interactive/__init__.py b/interactive/__init__.py new file mode 100644 index 0000000..06d1a46 --- /dev/null +++ b/interactive/__init__.py @@ -0,0 +1,71 @@ +from textual import on +from textual.app import App, ComposeResult +from textual.containers import Horizontal, Vertical +from textual.widgets import LoadingIndicator, SelectionList, Select, Label, Header +from textual.widgets.selection_list import Selection +from tunesynctool import SpotifyDriver, SubsonicDriver, Configuration +from tunesynctool.models import Playlist + +config = Configuration.from_env() + +class InteractiveApp(App): + CSS_PATH = "app.tcss" + + source = None + target = None + def __init__(self, **kwargs): + super().__init__(**kwargs) + self.source = None + self.target = None + + def compose(self) -> ComposeResult: + yield Header(name="Spotidrome") + yield Vertical( + Horizontal( + Select( + id="source", + prompt="Select source", + options=[('Subsonic', 'subsonic'), ('Spotify', 'spotify')] + ), + Select(id="target", prompt="Select target", options=[('Subsonic', 'subsonic'), ('Spotify', 'spotify')]), + classes="select-source-target", + ), + Vertical( + SelectionList( + id="playlist-list", + classes="playlist-list" + ), + classes="playlist-container", + ), + classes="main-container" + ) + + @on(Select.Changed) + def on_select_changed(self, event: Select.Changed) -> None: + if event.control.id == "source": + self.source = event.value + elif event.control.id == "target": + self.target = event.value + + if self.source and self.target: + self.load_playlists() + + def load_playlists(self): + # Load playlists + if self.source == 'spotify': + driver = SpotifyDriver(config) + elif self.source == 'subsonic': + driver = SubsonicDriver(config) + else: + raise ValueError("Invalid source") + + playlists = driver.get_user_playlists() + options = [(playlist.name, playlist.service_id) for playlist in playlists] + self.query_one("#playlist-list", expect_type=SelectionList).add_options(options) + self.query_one("#playlist-list", expect_type=SelectionList).refresh() + + @on(SelectionList.SelectedChanged) + def on_playlist_selected(self, event: SelectionList.SelectedChanged) -> None: + if event.control.id == "playlist-list": + selected_playlist = event.control.selected + # self.query_one(Label).update(f"Selected playlist: {selected_playlist}") \ No newline at end of file diff --git a/interactive/__pycache__/__init__.cpython-312.pyc b/interactive/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2a80decbcf614ebcec8bad308266432856cdb277 GIT binary patch literal 4056 zcmbVPT}&L;6}~gGGdue;%kJ`P8w@tF@n8dLo7k0b+PGkw#5QrEN~=k&(Pn4Bi)Vjw zXBNx~QWRM#G0 zBvN|qy+7yNduHxA-}&b74@C(hXrKP!Z{sG+KBWu4iQZ)EPcT_R1~NDcWjT%G=$yCs zte^?mfEHkD!4k8QCS`+KkgWrjoDFHAY*-6tBU&UI)uLHNQ$Q3&3tA1?My-)UJTmJiPWUghGv4#2S~HK%BSXG{jF2hZ6I`*@G96YU|Dg+& zBYZxm@aj3xZmkztMtMQWJDUd}ltPJxprO^8-WP8ABhPTIDI)85OnM^bl0 z;J5V>bid)2kW1%z1`E)UB<{Z0kAa9s`HpPK~sXDWB$v*#Sy@hGq3|30b&$^)3-w+3-eF(bG z=g@|%ECkDPOIbd=d~#JjTxr@rAGjG|!>z~`Y(hlBrc=bZXZ%Ke)(O9@ze0BbaR8(p z&l%i(-iO3*xh3$MQ}vSL0}weuILewKKrlr^8t3l^{j}Sqm5orX)(GE^RCn&!4pl8i zjp%*lo);-22D|-v-Ofq(-KNnWg(*&r50fyjvpFl2^HE|1=EP46b;f4`XUG|fY z$hMb;APssMN`fpzW7805K4TE60KqCaB$zMI+_dq&-9}wZlo|jLzzIF>GkQFva3si( zVcK6R1uvg_Xi}>@?gA^go0>{iRcT5;nVgABu`G-|)wL?(DBVw;jwRYruEx}3Du?&O zU{mCG;5O*tp)R+TnrblQ$s6hZDd_&qKoo0OKJg&dwJLXQ#F{puO&js1N^^VVKzF6> zg_Tp6R$7O*gMmbHJB$*|%g65iaOLck6}`AJIQbwxRcYznu9KD6b`mL#8}YVE^U+G{ z@oiB^BsXQWuV*_VDY4BMYCN*tnXC(Mp=2ohg-vhp_L+lcIyfSllaL$fYF2`V&M7Lk zc(~INWbXtlYTLx_6Q0uGt{nrfB;f>Per?;G?YZu6VU=fA6JKk!`m7l=L2p*m@IjEv zH9}b81juP7)-<1FIp8GvPZfq4jv4M$iAFc);Jn2UM8wIIRdj*QHjtPF-z(jRlnqFu z@W4IL+0^M%1{2aPD^du5rd~xB$^~iy8bVW&r0phj`2(%X4>vKQi5;wZ4RLE4S}5HXZS(1D5Uvul;*EMIA(3 zkHSv;9CRi4kOM$7hDW}oSf`Inmj^i#F|QYZIdx~cV5(6U>C_2C0-QrhgzM-c{2GP% zS&X6nO2S82FWM&FK{-CmHi2w1lQwl=?a-T$71Mei$drbRL{f&Kdkjv3*c`*AeHCbx zCI^uWw<-(yFJ}|kpJEku*c5^tv@wRo-+^VRttMTbO}rQAvAfXGTmi%{^e?NckAQIS{jt#iX|3Syi zUqiLk`~tIHo8=kd@xz!hjVjkX8weBz)-(6ev;naUu;sVSXSzwgaB) ztO?v+n+Cv)O+#Nxb-!4R^j12Ke5ib&taqF&!~bX-FjusX@s^sTg(Iy!pl}T9dNywq zEjo|t`kTd+KnV$^pFgvUIFvS_Bf8}6$5B8NO!2y?_@pq|+LeGVC-6*R$ zOvBgz2vkJzs?oG*S-K9@K`TgEb?}ml-Fj+(c9gR0ccAd{8`md-B7#K6q;r!Sv(jp3-4UKvE0SJxxZ% zVeYe5dPrH9kCf#jYvR#Oo)=Hu?OE?WU+zA?iD2=`;8Qx#gI(KH%bdvGZdlz%f{uCJ z0k1J`5-pZUov)qB7{D7gre9*_KevRUPGGeaIasr^ z*Toi;d^#=JutLp6onp?kr*mm14_{!)Q;eT5t;$LLZe=fo-n48?>6*x6P($iwZW2>k zVE4n6o!#rQqD?;SV&w;T1QfKIvrj{}DR3P32sJ%M-H*}t9;1Jn literal 0 HcmV?d00001 diff --git a/interactive/__pycache__/app.cpython-312.pyc b/interactive/__pycache__/app.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ea5a6870da11e871db9437de04286276bdd87c32 GIT binary patch literal 652 zcmY*WJ8#rL5T04vms7|&2@;P6bP+U0=-ferkWi3N1iAt`He57@e@*0P^MdfC}^OIbU^|tX3uv#R`NIV&EuQd^@m<>73du8zaJfu{bI@TcnfEC zgPbXF;Fv>!5f&_BXgSNB!i`)62KRtF6X34EL#OSFys;N_zF875Dky zP))86&}=-Y5}uW#osws1qAQuUy)Ci@nO!7j3IZbJ5HXIz*=3wfX!O_#T;uPQTF4~T z*>hpXbfnOYEK~eP%xYbsZ+4a7J|OAoKl#H&;ai*{!WiB;dl=wQ+7}4WxJu-^%2xM( z-3%XBg$SP{>C^CTl{SSawFu~|vmyT3gD|F(lgyhHM8 zo!~3{cm*H*%g28IxZD4!T#CK+H*gqurW?m)QiwP