-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 35cc5c4
Showing
12 changed files
with
436 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
/.bundle/ | ||
/.yardoc | ||
/_yardoc/ | ||
/coverage/ | ||
/doc/ | ||
/pkg/ | ||
/spec/reports/ | ||
/tmp/ | ||
Gemfile.lock | ||
.ruby-version | ||
*.gem | ||
|
||
# rspec failure tracking | ||
.rspec_status |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
# frozen_string_literal: true | ||
|
||
source 'https://rubygems.org' | ||
|
||
git_source(:github) {|repo_name| "https://github.com/#{repo_name}" } | ||
|
||
# Specify your gem's dependencies in aeries-api.gemspec | ||
gemspec |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
The MIT License (MIT) | ||
|
||
Copyright (c) 2022 Derek Povah <https://derekpovah.com> | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in | ||
all copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
THE SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
Shellify | ||
======== | ||
|
||
Use Spotify from the command line | ||
|
||
Installation | ||
------------ | ||
|
||
Add this line to your application's Gemfile: | ||
|
||
```bash | ||
$ gem install shellify | ||
``` | ||
|
||
#### Setup | ||
|
||
1. Create a Spotify application in the [Spotify Developer Dashboard](https://developer.spotify.com/dashboard). | ||
1. Get your Spotify OAUTH `access_token` and `refresh_token`. (Shelilfy currently doesn't currently implement a two way OAUTH flow, but Spotify has [sample apps](https://github.com/spotify/web-api-auth-examples) that you can use to get your initial keys. Shellify will handle exchanging refresh tokens for access tokens after initial setup.) | ||
1. Create two json files in `~/.config/shellify` | ||
`config.json` | ||
```json | ||
{ | ||
"client_id": "xxxxxxxxxxxxxxxx", | ||
"client_secret": "xxxxxxxxxxxxxxx" | ||
} | ||
``` | ||
|
||
`spotify_user.json` | ||
```json | ||
{ | ||
"id": "spotify_user_id", | ||
"token": "xxxxxxxxxxxxxxx", | ||
"refresh_token": "xxxxxxxxxxxxxxx" | ||
} | ||
``` | ||
|
||
Commands | ||
-------- | ||
|
||
``` | ||
$ shellify | ||
Now Playing: | ||
3 Libras - A Perfect Circle - 02:24/03:39 - ♥ | ||
``` | ||
See `shellify help` for a full list of commands. | ||
RSpotify | ||
-------- | ||
Shellify is basically a just a wrapper for [RSpotify](https://github.com/guilhermesad/rspotify) and wouldn't be possible (without significantly more effort) thanks to the work that's already been done over there. | ||
License | ||
------- | ||
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
#!/usr/bin/env ruby | ||
# frozen_string_literal: true | ||
|
||
require 'shellify' | ||
|
||
begin | ||
Shellify::Cli.new.run | ||
rescue Interrupt | ||
exit 1 | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
# frozen_string_literal: true | ||
|
||
require 'fileutils' | ||
require 'json' | ||
require 'rspotify' | ||
require 'shellify/version' | ||
|
||
module Shellify | ||
autoload :Cli, 'shellify/cli' | ||
autoload :Config, 'shellify/config' | ||
autoload :User, 'shellify/user' | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
# frozen_string_literal: true | ||
|
||
require 'commander' | ||
require 'shellify/utils' | ||
|
||
module Shellify | ||
class Cli | ||
include Commander::Methods | ||
include Shellify::Utils | ||
|
||
def initialize | ||
$VERBOSE = nil # Suppress warnings from RSpotify's rest-client implementation by default | ||
@config = Shellify::Config.new | ||
@user = Shellify::User.new(@config.config_dir) | ||
end | ||
|
||
def run | ||
program :name, 'Shellify' | ||
program :version, Shellify::VERSION | ||
program :description, 'Use Spotify from the command line' | ||
|
||
command :devices do |c| | ||
c.description = 'List available playback devices' | ||
c.action do | ||
devices = @user.devices | ||
devices.each do |device| | ||
puts " #{device.name}#{" - \e[1m𝅘𝅥𝅮\e[22m" if device.is_active}" | ||
end | ||
end | ||
end | ||
|
||
command :playing do |c| | ||
c.description = 'List information about the current song' | ||
c.action do | ||
return puts " Nothing playing" unless @user.player.playing? | ||
|
||
print_current_song | ||
end | ||
end | ||
|
||
command :volume do |c| | ||
c.description = 'Set the volume of the current playback device' | ||
c.action do |args, options| | ||
@user.player.volume(args[0]) | ||
end | ||
end | ||
|
||
command :like do |c| | ||
c.description = 'Save the current song to your library' | ||
c.action do | ||
@user.save_tracks!([@user.player.currently_playing]) | ||
end | ||
end | ||
|
||
command :unlike do |c| | ||
c.description = 'Remove the current song from your library' | ||
c.action do | ||
@user.remove_tracks!([@user.player.currently_playing]) | ||
end | ||
end | ||
|
||
command :playlists do |c| | ||
c.description = 'List your playlists' | ||
c.action do | ||
@user.playlists.each do |playlist| | ||
puts " #{playlist.name} - #{playlist.owner.display_name}#{" - Collaborative" if playlist.collaborative}" | ||
end | ||
end | ||
end | ||
|
||
command :add do |c| | ||
c.description = 'Add the current song to the provided playlist' | ||
c.action do |args, options| | ||
return puts " Nothing playing" unless @user.player.playing? | ||
|
||
playlist = @user.playlists.find { |p| p.name == args[0] } | ||
return puts " Playlist not found" unless playlist | ||
|
||
playlist.add_tracks!([@user.player.currently_playing]) | ||
end | ||
end | ||
|
||
command :remove do |c| | ||
c.description = 'Remove the currently playing song from the provided playlist' | ||
c.action do |args, options| | ||
return puts " Nothing playing" unless @user.player.playing? | ||
|
||
playlist = @user.playlists.find { |p| p.name == args[0] } | ||
return puts " Playlist not found" unless playlist | ||
|
||
playlist.remove_tracks!([@user.player.currently_playing]) | ||
end | ||
end | ||
|
||
command :play do |c| | ||
c.description = 'Play or Pause on the currently playing device' | ||
c.action do | ||
begin | ||
if @user.player.playing? | ||
@user.player.pause | ||
else | ||
@user.player.play | ||
print_current_song | ||
end | ||
rescue RestClient::NotFound | ||
@user.player.play(@user.devices.first.id) | ||
end | ||
end | ||
end | ||
|
||
command :next do |c| | ||
c.description = 'Skip to the next song in the queue' | ||
c.action do | ||
@user.player.next | ||
print_current_song | ||
end | ||
end | ||
|
||
command :previous do |c| | ||
c.description = 'Skip the the previous song in the queue' | ||
c.action do | ||
@user.player.previous | ||
print_current_song | ||
end | ||
end | ||
|
||
command :restart do |c| | ||
c.description = 'Restart the currently playing song' | ||
c.action do | ||
@user.player.seek 0 | ||
print_current_song | ||
end | ||
end | ||
|
||
command :seek do |c| | ||
c.description = 'Seek to the specified time in the current song' | ||
c.action do |args, option| | ||
@user.player.seek(time_to_ms(args[0])) | ||
print_current_song | ||
end | ||
end | ||
|
||
default_command :playing | ||
alias_command :pause, :play | ||
alias_command :back, :previous | ||
alias_command :skip, :next | ||
|
||
run! | ||
end | ||
|
||
private | ||
|
||
def print_current_song | ||
playing = @user.player.currently_playing | ||
puts ' Now Playing:' | ||
puts " #{playing.name} - #{playing.artists.first.name} - "\ | ||
"#{duration_to_s(@user.player.progress)}/#{duration_to_s(playing.duration_ms)}"\ | ||
"#{" - ♥" if @user.saved_tracks?([playing]).first}" | ||
end | ||
|
||
def exit_with_message(message, code = 1) | ||
puts message | ||
exit code | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
# frozen_string_literal: true | ||
|
||
module Shellify | ||
class Config | ||
attr_reader :client_id, :client_secret, :config_dir | ||
|
||
CONFIG_DIR = ENV['HOME'] + '/.config/shellify' | ||
CONFIG_FILE = CONFIG_DIR + '/config.json' | ||
|
||
def initialize | ||
@config_dir = CONFIG_DIR | ||
@config_file = CONFIG_FILE | ||
create_config_file | ||
load_config | ||
RSpotify.authenticate(@client_id, @client_secret) | ||
end | ||
|
||
private | ||
|
||
def load_config | ||
JSON.parse(File.read(CONFIG_FILE)).each_pair { |k,v| instance_variable_set("@#{k}", v) } | ||
end | ||
|
||
def create_config_file | ||
return if File.exists?(CONFIG_FILE) | ||
|
||
FileUtils.mkdir_p(CONFIG_DIR) | ||
FileUtils.touch(CONFIG_FILE) | ||
write_default_config | ||
end | ||
|
||
def write_default_config | ||
File.open(CONFIG_FILE, 'w') do |file| | ||
file.write(JSON.pretty_generate({client_id: '', client_secret: ''})) | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
# frozen_string_literal: true | ||
|
||
module Shellify | ||
class User < RSpotify::User | ||
|
||
USER_FILE = '/spotify_user.json' | ||
|
||
def initialize(config_dir) | ||
@config_dir = config_dir | ||
create_user_file | ||
@spotify_user = load_persisted_user | ||
super({ | ||
'credentials' => { | ||
'token' => @spotify_user.token, | ||
'refresh_token' => @spotify_user.refresh_token, | ||
'access_refresh_callback' => access_refresh_callback, | ||
}, | ||
'id' => @spotify_user.id, | ||
}) | ||
end | ||
|
||
private | ||
|
||
def load_persisted_user | ||
OpenStruct.new(JSON.parse(File.read(@config_dir + USER_FILE))) | ||
end | ||
|
||
def persist_user(access_token) | ||
@spotify_user.token = access_token | ||
|
||
File.open(@config_dir + USER_FILE, 'w') do |file| | ||
file.write(JSON.pretty_generate(@spotify_user.to_h)) | ||
end | ||
end | ||
|
||
def access_refresh_callback | ||
Proc.new do |new_access_token, _token_lifetime| | ||
persist_user(new_access_token) | ||
end | ||
end | ||
|
||
def create_user_file | ||
return if File.exists?(@config_dir + USER_FILE) | ||
|
||
FileUtils.mkdir_p(CONFIG_DIR) | ||
FileUtils.touch(@config_dir + USER_FILE) | ||
end | ||
end | ||
end |
Oops, something went wrong.