chronicle-spotify 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 230610bca1ab6354681e21b3702832d04ac8e2b134e940acd7535da96f1466d5
4
- data.tar.gz: b8cab459d2173718113607ef4bb051c6eea6a21eb39df849e13ce95a3f5d4ab7
3
+ metadata.gz: 05a2aa0279eb07b82642feb0b1a13b0e1d7e696325bc80316bef77ed5a44e6fd
4
+ data.tar.gz: 5dee1d598b949ca4c5d916005123b859d7bf00eb4d046fb40b0d2bfe74336357
5
5
  SHA512:
6
- metadata.gz: 8bc73fad90e5ae81719fd657949716095cbb2dce117dabb5106879c2b480969b772a5b4290220a59b969a596c7f1af989b0919eec6bdc443456b3386da5560f8
7
- data.tar.gz: bd1034b1496925f9ca1db1d06de634d4738e447bb051eacffc730fa8469adfbbb654640d6aa75275629981dd7243266f6004f631a19d80b2bc5a8aadd69efe6c
6
+ metadata.gz: 2c2833de89d8ed0698ff984e724c1f47be7f714553811b6bd14247d2fb6e3962cce7745ba478ce4d6ddf8d992144bcd9db23dc4ab52d0c49d13376da80f59b00
7
+ data.tar.gz: faa9603a26db4d4a2ea0cdaed98d164cb3fec7fe6e13139b045fb7cfd492771b7b0956c6934d0327dd69a8140e93ccb10640f1580ce2f4caa1dbd4cfc0f8e8ba
data/.gitignore CHANGED
@@ -7,4 +7,6 @@
7
7
  /spec/reports/
8
8
  /tmp/
9
9
 
10
+ Gemfile.lock
11
+
10
12
  .DS_Store
data/.rubocop.yml CHANGED
@@ -1,44 +1,2 @@
1
- AllCops:
2
- EnabledByDefault: true
3
- TargetRubyVersion: 2.7
4
-
5
- Style/FrozenStringLiteralComment:
6
- SafeAutoCorrect: true
7
-
8
- Style/StringLiterals:
9
- Enabled: false
10
-
11
- Layout/MultilineAssignmentLayout:
12
- Enabled: false
13
-
14
- Layout/MultilineMethodCallIndentation:
15
- EnforcedStyle: indented
16
-
17
- Layout/RedundantLineBreak:
18
- Enabled: false
19
-
20
- Style/MethodCallWithArgsParentheses:
21
- Enabled: false
22
-
23
- Style/MethodCalledOnDoEndBlock:
24
- Exclude:
25
- - 'spec/**/*'
26
-
27
- Style/OpenStructUse:
28
- Enabled: false
29
-
30
- Style/Copyright:
31
- Enabled: false
32
-
33
- Style/MissingElse:
34
- Enabled: false
35
-
36
- Style/SymbolArray:
37
- EnforcedStyle: brackets
38
-
39
- Style/WordArray:
40
- EnforcedStyle: brackets
41
-
42
- Lint/ConstantResolution:
43
- Enabled: false
44
-
1
+ inherit_gem:
2
+ chronicle-core: .rubocop-plugin.yml
data/Gemfile CHANGED
@@ -1,8 +1,6 @@
1
- # frozen_string_literal: true
2
-
3
- source "https://rubygems.org"
1
+ source 'https://rubygems.org'
4
2
 
5
3
  # Specify your gem's dependencies in chronicle-spotify.gemspec
6
4
  gemspec
7
5
 
8
- gem "rake", "~> 13.0"
6
+ gem 'rake', '~> 13.0'
data/README.md CHANGED
@@ -36,15 +36,18 @@ This will open a browser window to authorize on spotify.com. When the flow is co
36
36
  ### 4. Use the the plugin
37
37
  ```sh
38
38
  # Extract recent limits
39
- $ chronicle-etl --extractor spotify:listens --limit 10
39
+ $ chronicle-etl --extractor spotify:listen --limit 10
40
40
 
41
41
  # Extract liked tracks from the last week
42
- $ chronicle-etl --extractor spotify:liked-tracks --since 1w
42
+ $ chronicle-etl --extractor spotify:like --since 1w
43
43
  # Transform as Chronicle Schema
44
- $ chronicle-etl --extractor spotify:liked-tracks --since 1w --transformer chronicle:like --loader json
44
+ $ chronicle-etl --extractor spotify:like --since 1w --schema chronicle
45
45
 
46
46
  # Extract saved albums
47
- $ chronicle-etl --extractor spotify:saved-albums --limit 10
47
+ $ chronicle-etl --extractor spotify:saved-album --limit 10
48
+
49
+ # Display a table of album names you've liked in last week
50
+ $ chronicle-etl --extractor spotify:saved-album --since 1w --schema chronicle --loader table --fields end_time object.name
48
51
  ```
49
52
 
50
53
  ## Available Connectors
@@ -52,26 +55,16 @@ $ chronicle-etl --extractor spotify:saved-albums --limit 10
52
55
 
53
56
  All the extractors expect `uid`, `access_token` and `refresh_token` to be available in your Chronicle secrets. After doing the authorization flow, you can verify that they exist using: `$ chronicle-etl secrets:list spotify`
54
57
 
55
- #### `liked-tracks`
58
+ #### `like`
56
59
 
57
60
  Extractor for your Spotify liked tracks
58
61
 
59
- #### `saved-albums`
62
+ #### `saved-album`
60
63
 
61
64
  Extractor for your Spotify saved albums
62
- #### `listens`
63
-
64
- Extractor for your recent listens. Due to API limitations, only your 50 most recent
65
-
66
- ### Transformers
67
-
68
- #### `like`
69
-
70
- Transform a like (either from `saved-albums` or `liked-tracks`) into Chronicle Schema
71
-
72
65
  #### `listen`
73
66
 
74
- Transforms a listen (from `listens`) into Chronicle Schema
67
+ Extractor for your recent listens. Due to API limitations, only your 50 most recent
75
68
 
76
69
  ## Roadmap
77
70
  - extractor for playlist activity ([#3](https://github.com/chronicle-app/chronicle-spotify/issues/3))
data/Rakefile CHANGED
@@ -1,4 +1,2 @@
1
- # frozen_string_literal: true
2
-
3
- require "bundler/gem_tasks"
1
+ require 'bundler/gem_tasks'
4
2
  task default: %i[]
data/bin/console CHANGED
@@ -1,15 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
2
 
4
- require "bundler/setup"
5
- require "chronicle/spotify"
3
+ require 'bundler/setup'
4
+ require 'chronicle/spotify'
6
5
 
7
- # You can add fixtures and/or initialization code here to make experimenting
8
- # with your gem easier. You can also use a different console, if you like.
9
-
10
- # (If you use this, don't forget to add pry to your Gemfile!)
11
- # require "pry"
6
+ require 'pry'
12
7
  Pry.start
13
-
14
- # require "irb"
15
- # IRB.start(__FILE__)
@@ -1,47 +1,48 @@
1
- # frozen_string_literal: true
2
-
3
- lib = File.expand_path("../lib", __FILE__)
1
+ lib = File.expand_path('lib', __dir__)
4
2
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
- require "chronicle/spotify/version"
3
+ require 'chronicle/spotify/version'
6
4
 
7
5
  Gem::Specification.new do |spec|
8
- spec.name = "chronicle-spotify"
6
+ spec.name = 'chronicle-spotify'
9
7
  spec.version = Chronicle::Spotify::VERSION
10
- spec.authors = ["Andrew Louis"]
11
- spec.email = ["andrew@hyfen.net"]
8
+ spec.authors = ['Andrew Louis']
9
+ spec.email = ['andrew@hyfen.net']
12
10
 
13
- spec.summary = "Spotify importer for Chronicle"
14
- spec.description = "Spotify connectors"
15
- spec.homepage = "https://github.com/chronicle-app/chronicle-spotify"
11
+ spec.summary = 'Spotify importer for Chronicle'
12
+ spec.description = 'Spotify connectors'
13
+ spec.homepage = 'https://github.com/chronicle-app/chronicle-spotify'
16
14
 
17
15
  # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
18
16
  # to allow pushing to a single host or delete this section to allow pushing to any host.
19
17
  if spec.respond_to?(:metadata)
20
- spec.metadata['allowed_push_host'] = "https://rubygems.org"
18
+ spec.metadata['allowed_push_host'] = 'https://rubygems.org'
21
19
 
22
- spec.metadata["homepage_uri"] = spec.homepage
23
- spec.metadata["source_code_uri"] = "https://github.com/chronicle-app/chronicle-spotify"
24
- spec.metadata["changelog_uri"] = "https://github.com/chronicle-app/chronicle-spotify"
20
+ spec.metadata['homepage_uri'] = spec.homepage
21
+ spec.metadata['source_code_uri'] = 'https://github.com/chronicle-app/chronicle-spotify'
22
+ spec.metadata['changelog_uri'] = 'https://github.com/chronicle-app/chronicle-spotify'
25
23
  else
26
- raise "RubyGems 2.0 or newer is required to protect against " \
27
- "public gem pushes."
24
+ raise 'RubyGems 2.0 or newer is required to protect against ' \
25
+ 'public gem pushes.'
28
26
  end
29
27
 
30
28
  # Specify which files should be added to the gem when it is released.
31
29
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
32
- spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
30
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
33
31
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
34
32
  end
35
- spec.bindir = "exe"
33
+ spec.bindir = 'exe'
36
34
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
37
- spec.require_paths = ["lib"]
38
-
39
- spec.add_dependency "chronicle-etl", "~> 0.5"
40
- spec.add_dependency "omniauth-spotify"
41
- spec.add_dependency "rspotify", "~> 2.11"
42
-
43
- spec.add_development_dependency "rubocop"
44
- spec.add_development_dependency "bundler", "~> 2.3"
45
- spec.add_development_dependency "rake", "~> 13.0.6"
46
- spec.add_development_dependency "pry-byebug", "~> 3.9"
35
+ spec.require_paths = ['lib']
36
+ spec.required_ruby_version = '>= 3.1'
37
+ spec.metadata['rubygems_mfa_required'] = 'true'
38
+
39
+ spec.add_dependency 'chronicle-core', '~> 0.3'
40
+ spec.add_dependency 'chronicle-etl', '~> 0.6'
41
+ spec.add_dependency 'omniauth-spotify'
42
+ spec.add_dependency 'rspotify', '~> 2.11'
43
+
44
+ spec.add_development_dependency 'bundler', '~> 2.3'
45
+ spec.add_development_dependency 'pry-byebug', '~> 3.10'
46
+ spec.add_development_dependency 'rake', '~> 13.0'
47
+ spec.add_development_dependency 'rubocop', '~> 1.63'
47
48
  end
@@ -5,13 +5,20 @@ module Chronicle
5
5
  class Authorizer < Chronicle::ETL::OauthAuthorizer
6
6
  provider :spotify
7
7
  omniauth_strategy :spotify
8
- scope 'user-read-recently-played playlist-read-private playlist-read-collaborative user-read-private user-read-email user-library-read'
9
- pluck_secrets({
10
- access_token: [:credentials, :token],
11
- refresh_token: [:credentials, :refresh_token],
8
+ scope %w[
9
+ user-read-recently-played
10
+ playlist-read-private
11
+ playlist-read-collaborative
12
+ user-read-private
13
+ user-read-email
14
+ user-library-read
15
+ ].join(' ')
16
+ pluck_secrets({
17
+ access_token: %i[credentials token],
18
+ refresh_token: %i[credentials refresh_token],
12
19
  uid: [:uid],
13
- name: [:info, :name],
14
- email: [:info, :email],
20
+ name: %i[info name],
21
+ email: %i[info email]
15
22
  })
16
23
  end
17
24
  end
@@ -1,95 +1,73 @@
1
+ require 'chronicle/models'
2
+
1
3
  module Chronicle
2
4
  module Spotify
3
5
  module Builders
4
- def build_listen(track:, timestamp:, actor:)
5
- record = ::Chronicle::ETL::Models::Activity.new({
6
- verb: 'listened',
7
- provider: 'spotify',
8
- end_at: timestamp
9
- })
10
- record.dedupe_on << [:provider, :verb, :end_at]
11
- record.actor = build_actor(actor)
12
- record.involved = build_track(track)
13
- record
6
+ def build_listen(record:, agent:)
7
+ Chronicle::Models::ListenAction.new do |r|
8
+ r.end_time = record[:played_at]
9
+ r.object = build_track(record[:track])
10
+ r.agent = build_agent(agent)
11
+ r.source = 'spotify'
12
+ r.dedupe_on << %i[type source end_time]
13
+ end
14
14
  end
15
15
 
16
- def build_liked(object:, timestamp:, actor:)
17
- record = ::Chronicle::ETL::Models::Activity.new({
18
- verb: 'liked',
19
- provider: 'spotify',
20
- end_at: timestamp
21
- })
22
- record.dedupe_on << [:provider, :verb, :end_at]
23
- record.actor = build_actor(actor)
16
+ def build_like(record:, agent:)
17
+ Chronicle::Models::LikeAction.new do |r|
18
+ r.end_time = record[:added_at]
24
19
 
25
- record.involved = if object[:album_type]
26
- build_album(object)
27
- else
28
- build_track(object)
29
- end
20
+ r.object = if record[:album]
21
+ build_album(record[:album])
22
+ elsif record[:track]
23
+ build_track(record[:track])
24
+ end
30
25
 
31
- record
26
+ r.agent = build_agent(agent)
27
+ r.source = 'spotify'
28
+ r.dedupe_on << %i[type source end_time]
29
+ end
32
30
  end
33
31
 
34
32
  def build_track(track)
35
- record = ::Chronicle::ETL::Models::Entity.new({
36
- represents: 'song',
37
- provider: 'spotify',
38
- provider_id: track[:id],
39
- title: track[:name],
40
- })
41
-
42
- record.creators = track[:artists].map{ |creator| build_creator(creator) }
43
- record.containers = build_album(track[:album])
44
- record.dedupe_on << [:provider, :provider_id, :represents]
45
- record
33
+ Chronicle::Models::MusicRecording.new do |r|
34
+ r.name = track[:name]
35
+ r.in_album = [build_album(track[:album])]
36
+ r.by_artist = track[:artists].map { |artist| build_artist(artist) }
37
+ r.duration = "PT#{track[:duration_ms] / 1000.0}S"
38
+ r.source = 'spotify'
39
+ r.source_id = track[:id]
40
+ r.dedupe_on = [[:url], %i[source_id source type]]
41
+ end
46
42
  end
47
43
 
48
- def build_creator(artist)
49
- record = ::Chronicle::ETL::Models::Entity.new({
50
- represents: 'musicartist',
51
- provider: 'spotify',
52
- provider_id: artist[:id],
53
- provider_url: artist[:external_urls][:spotify],
54
- title: artist[:name],
55
- })
56
- record.dedupe_on << [:provider_url]
57
- record.dedupe_on << [:provider, :provider_id, :represents]
58
- record
44
+ def build_artist(artist)
45
+ Chronicle::Models::MusicGroup.new do |r|
46
+ r.name = artist[:name]
47
+ r.url = artist[:external_urls][:spotify]
48
+ r.source = 'spotify'
49
+ r.source_id = artist[:id]
50
+ end
59
51
  end
60
52
 
61
53
  def build_album(album)
62
- record = ::Chronicle::ETL::Models::Entity.new({
63
- represents: 'album',
64
- provider: 'spotify',
65
- provider_id: album[:id],
66
- provider_url: album[:external_urls][:spotify],
67
- title: album[:name],
68
- })
69
- record.attachments = build_image(album[:images].first[:url])
70
- record.dedupe_on << [:provider_url]
71
- record.dedupe_on << [:provider, :provider_id, :represents]
72
- record
73
- end
74
-
75
- def build_image(image_url)
76
- ::Chronicle::ETL::Models::Attachment.new({
77
- url_original: image_url
78
- })
54
+ Chronicle::Models::MusicAlbum.new do |r|
55
+ r.name = album[:name]
56
+ r.source = 'spotify'
57
+ r.source_id = album[:id]
58
+ r.image = album[:images].first[:url]
59
+ r.url = album[:external_urls][:spotify]
60
+ end
79
61
  end
80
62
 
81
- def build_actor(actor)
82
- record = ::Chronicle::ETL::Models::Entity.new({
83
- represents: 'identity',
84
- provider: 'spotify',
85
- provider_id: actor[:id],
86
- provider_url: actor[:external_urls][:spotify],
87
- slug: actor[:id],
88
- title: actor[:display_name]
89
- })
90
- record.dedupe_on << [:provider_url]
91
- record.dedupe_on << [:provider, :provider_id, :represents]
92
- record
63
+ def build_agent(agent)
64
+ Chronicle::Models::Person.new do |r|
65
+ r.name = agent[:display_name]
66
+ r.url = agent[:external_urls][:spotify]
67
+ r.source = 'spotify'
68
+ r.slug = agent[:id]
69
+ r.source_id = agent[:id]
70
+ end
93
71
  end
94
72
  end
95
73
  end
@@ -4,31 +4,16 @@ module Chronicle
4
4
  include Chronicle::Spotify::Builders
5
5
 
6
6
  register_connector do |r|
7
- r.provider = 'spotify'
8
- r.description = 'a spotify track'
9
- r.identifier = 'like'
7
+ r.source = :spotify
8
+ r.type = :like
9
+ r.strategy = :api
10
+ r.description = 'a like'
11
+ r.from_schema = :extraction
12
+ r.to_schema = :chronicle
10
13
  end
11
14
 
12
- def transform
13
- build_liked(
14
- timestamp: timestamp,
15
- object: object,
16
- actor: @extraction.meta[:actor]
17
- )
18
- end
19
-
20
- def id
21
- object[:id]
22
- end
23
-
24
- def timestamp
25
- Time.parse(@extraction.data[:added_at])
26
- end
27
-
28
- private
29
-
30
- def object
31
- @object = @extraction.data[:track] || @extraction.data[:album]
15
+ def transform(record)
16
+ build_like(record: record.data, agent: record.extraction.meta[:agent])
32
17
  end
33
18
  end
34
19
  end
@@ -2,14 +2,15 @@ module Chronicle
2
2
  module Spotify
3
3
  class SavedTracksExtractor < Chronicle::Spotify::SpotifyExtractor
4
4
  register_connector do |r|
5
- r.provider = 'spotify'
5
+ r.source = :spotify
6
+ r.type = :like
7
+ r.strategy = :api
6
8
  r.description = 'liked tracks'
7
- r.identifier = 'liked-tracks'
8
9
  end
9
10
 
10
11
  def extract
11
12
  @proxy.saved_tracks(after: @config.since, limit: @config.limit) do |item|
12
- yield Chronicle::ETL::Extraction.new(data: item, meta: { actor: @actor })
13
+ yield build_extraction(data: item, meta: { agent: @agent })
13
14
  end
14
15
  end
15
16
  end
@@ -4,25 +4,16 @@ module Chronicle
4
4
  include Chronicle::Spotify::Builders
5
5
 
6
6
  register_connector do |r|
7
- r.provider = 'spotify'
8
- r.description = 'a spotify listen'
9
- r.identifier = 'listen'
7
+ r.source = :spotify
8
+ r.type = :listen
9
+ r.strategy = :api
10
+ r.description = 'a listen'
11
+ r.from_schema = :extraction
12
+ r.to_schema = :chronicle
10
13
  end
11
14
 
12
- def transform
13
- build_listen(
14
- timestamp: timestamp,
15
- track: @extraction.data[:track],
16
- actor: @extraction.meta[:actor]
17
- )
18
- end
19
-
20
- def id
21
- @extraction.data[:track][:id]
22
- end
23
-
24
- def timestamp
25
- Time.parse(@extraction.data[:played_at])
15
+ def transform(record)
16
+ build_listen(record: record.data, agent: record.extraction.meta[:agent])
26
17
  end
27
18
  end
28
19
  end
@@ -2,14 +2,15 @@ module Chronicle
2
2
  module Spotify
3
3
  class ListenedExtractor < Chronicle::Spotify::SpotifyExtractor
4
4
  register_connector do |r|
5
- r.provider = 'spotify'
6
- r.description = 'listened tracks'
7
- r.identifier = 'listens'
5
+ r.source = :spotify
6
+ r.type = :listen
7
+ r.strategy = :api
8
+ r.description = 'listens'
8
9
  end
9
10
 
10
11
  def extract
11
12
  @proxy.recently_played(after: @config.since, limit: @config.limit, before: @config.until) do |item|
12
- yield Chronicle::ETL::Extraction.new(data: item, meta: { actor: @actor })
13
+ yield build_extraction(data: item, meta: { agent: @agent })
13
14
  end
14
15
  end
15
16
  end
@@ -22,28 +22,28 @@ module Chronicle
22
22
  JSON.parse(RSpotify::User.find(@authenticated_user.id), symbolize_names: true)
23
23
  end
24
24
 
25
- def saved_albums(after: nil, limit:, &block)
26
- retrieve_all(method: :saved_albums, after: after, limit: limit, &block)
25
+ def saved_albums(limit:, after: nil, &block)
26
+ retrieve_all(method: :saved_albums, after:, limit:, &block)
27
27
  end
28
28
 
29
- def saved_tracks(after: nil, limit:, &block)
30
- retrieve_all(method: :saved_tracks, after: after, limit: limit, &block)
29
+ def saved_tracks(limit:, after: nil, &block)
30
+ retrieve_all(method: :saved_tracks, after:, limit:, &block)
31
31
  end
32
32
 
33
33
  def recently_played(before: nil, after: nil, limit: nil, &block)
34
34
  before = before&.to_i&.*(1000)
35
- retrieve_all(method: :recently_played, before: before, after: after, limit: limit, &block)
35
+ retrieve_all(method: :recently_played, before:, after:, limit:, &block)
36
36
  end
37
37
 
38
38
  private
39
39
 
40
- def retrieve_all(method:, before: nil, after: nil, limit: nil)
40
+ def retrieve_all(method:, before: nil, after: nil, limit: nil, &block)
41
41
  has_more = true
42
42
  count = 0
43
- offset = 0 if method != :recently_played # FIXME: hacky
43
+ offset = 0 if method != :recently_played # FIXME: hacky
44
44
 
45
45
  while has_more
46
- response = retrieve_page(method: method, before: before, offset: offset)
46
+ response = retrieve_page(method:, before:, offset:)
47
47
 
48
48
  records = response[:items]
49
49
  records = records.first(limit - count) if limit
@@ -51,9 +51,7 @@ module Chronicle
51
51
 
52
52
  break unless records.any?
53
53
 
54
- records.each do |track|
55
- yield track
56
- end
54
+ records.each(&block)
57
55
 
58
56
  count += records.count
59
57
  has_more = response[:next]
@@ -65,9 +63,9 @@ module Chronicle
65
63
 
66
64
  def retrieve_page(method:, before: nil, offset: nil)
67
65
  options = {
68
- offset: offset,
66
+ offset:,
69
67
  limit: PER_PAGE,
70
- before: before
68
+ before:
71
69
  }.compact
72
70
 
73
71
  JSON.parse(@authenticated_user.send(method, **options), symbolize_names: true)
@@ -0,0 +1,18 @@
1
+ module Chronicle
2
+ module Spotify
3
+ class SavedAlbumExtractor < Chronicle::Spotify::SpotifyExtractor
4
+ register_connector do |r|
5
+ r.source = :spotify
6
+ r.type = :saved_album
7
+ r.strategy = :api
8
+ r.description = 'saved_albums'
9
+ end
10
+
11
+ def extract
12
+ @proxy.saved_albums(after: @config.since, limit: @config.limit) do |item|
13
+ yield build_extraction(data: item, meta: { agent: @agent })
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,20 @@
1
+ module Chronicle
2
+ module Spotify
3
+ class SavedAlbumTransformer < Chronicle::ETL::Transformer
4
+ include Chronicle::Spotify::Builders
5
+
6
+ register_connector do |r|
7
+ r.source = :spotify
8
+ r.type = :saved_album
9
+ r.strategy = :api
10
+ r.description = 'a saved album'
11
+ r.from_schema = :extraction
12
+ r.to_schema = :chronicle
13
+ end
14
+
15
+ def transform(record)
16
+ build_like(record: record.data, agent: record.extraction.meta[:agent])
17
+ end
18
+ end
19
+ end
20
+ end
@@ -15,7 +15,7 @@ module Chronicle
15
15
  client_id: @config.client_id,
16
16
  client_secret: @config.client_secret
17
17
  )
18
- @actor = @proxy.user
18
+ @agent = @proxy.user
19
19
  end
20
20
  end
21
21
  end
@@ -1,7 +1,5 @@
1
- # frozen_string_literal: true
2
-
3
1
  module Chronicle
4
2
  module Spotify
5
- VERSION = "0.1.0"
3
+ VERSION = '0.2.0'.freeze
6
4
  end
7
5
  end
@@ -1,20 +1,19 @@
1
- # frozen_string_literal: true
2
-
3
1
  require 'chronicle/etl'
4
2
 
5
- require_relative "spotify/version"
3
+ require_relative 'spotify/version'
6
4
 
7
- require_relative "spotify/authorizer"
8
- require_relative "spotify/proxy"
9
- require_relative "spotify/builders"
5
+ require_relative 'spotify/authorizer'
6
+ require_relative 'spotify/proxy'
7
+ require_relative 'spotify/builders'
10
8
 
11
- require_relative "spotify/spotify_extractor"
12
- require_relative "spotify/listens_extractor"
13
- require_relative "spotify/liked_tracks_extractor"
14
- require_relative "spotify/saved_albums_extractor"
9
+ require_relative 'spotify/spotify_extractor'
10
+ require_relative 'spotify/listens_extractor'
11
+ require_relative 'spotify/liked_tracks_extractor'
12
+ require_relative 'spotify/saved_album_extractor'
13
+ require_relative 'spotify/saved_album_transformer'
15
14
 
16
- require_relative "spotify/like_transformer"
17
- require_relative "spotify/listen_transformer"
15
+ require_relative 'spotify/like_transformer'
16
+ require_relative 'spotify/listen_transformer'
18
17
  module Chronicle
19
18
  module Spotify
20
19
  end
metadata CHANGED
@@ -1,29 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chronicle-spotify
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Louis
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-04-24 00:00:00.000000000 Z
11
+ date: 2024-04-30 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: chronicle-core
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.3'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.3'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: chronicle-etl
15
29
  requirement: !ruby/object:Gem::Requirement
16
30
  requirements:
17
31
  - - "~>"
18
32
  - !ruby/object:Gem::Version
19
- version: '0.5'
33
+ version: '0.6'
20
34
  type: :runtime
21
35
  prerelease: false
22
36
  version_requirements: !ruby/object:Gem::Requirement
23
37
  requirements:
24
38
  - - "~>"
25
39
  - !ruby/object:Gem::Version
26
- version: '0.5'
40
+ version: '0.6'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: omniauth-spotify
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -53,61 +67,61 @@ dependencies:
53
67
  - !ruby/object:Gem::Version
54
68
  version: '2.11'
55
69
  - !ruby/object:Gem::Dependency
56
- name: rubocop
70
+ name: bundler
57
71
  requirement: !ruby/object:Gem::Requirement
58
72
  requirements:
59
- - - ">="
73
+ - - "~>"
60
74
  - !ruby/object:Gem::Version
61
- version: '0'
75
+ version: '2.3'
62
76
  type: :development
63
77
  prerelease: false
64
78
  version_requirements: !ruby/object:Gem::Requirement
65
79
  requirements:
66
- - - ">="
80
+ - - "~>"
67
81
  - !ruby/object:Gem::Version
68
- version: '0'
82
+ version: '2.3'
69
83
  - !ruby/object:Gem::Dependency
70
- name: bundler
84
+ name: pry-byebug
71
85
  requirement: !ruby/object:Gem::Requirement
72
86
  requirements:
73
87
  - - "~>"
74
88
  - !ruby/object:Gem::Version
75
- version: '2.3'
89
+ version: '3.10'
76
90
  type: :development
77
91
  prerelease: false
78
92
  version_requirements: !ruby/object:Gem::Requirement
79
93
  requirements:
80
94
  - - "~>"
81
95
  - !ruby/object:Gem::Version
82
- version: '2.3'
96
+ version: '3.10'
83
97
  - !ruby/object:Gem::Dependency
84
98
  name: rake
85
99
  requirement: !ruby/object:Gem::Requirement
86
100
  requirements:
87
101
  - - "~>"
88
102
  - !ruby/object:Gem::Version
89
- version: 13.0.6
103
+ version: '13.0'
90
104
  type: :development
91
105
  prerelease: false
92
106
  version_requirements: !ruby/object:Gem::Requirement
93
107
  requirements:
94
108
  - - "~>"
95
109
  - !ruby/object:Gem::Version
96
- version: 13.0.6
110
+ version: '13.0'
97
111
  - !ruby/object:Gem::Dependency
98
- name: pry-byebug
112
+ name: rubocop
99
113
  requirement: !ruby/object:Gem::Requirement
100
114
  requirements:
101
115
  - - "~>"
102
116
  - !ruby/object:Gem::Version
103
- version: '3.9'
117
+ version: '1.63'
104
118
  type: :development
105
119
  prerelease: false
106
120
  version_requirements: !ruby/object:Gem::Requirement
107
121
  requirements:
108
122
  - - "~>"
109
123
  - !ruby/object:Gem::Version
110
- version: '3.9'
124
+ version: '1.63'
111
125
  description: Spotify connectors
112
126
  email:
113
127
  - andrew@hyfen.net
@@ -119,7 +133,6 @@ files:
119
133
  - ".rubocop.yml"
120
134
  - CODE_OF_CONDUCT.md
121
135
  - Gemfile
122
- - Gemfile.lock
123
136
  - README.md
124
137
  - Rakefile
125
138
  - bin/console
@@ -133,7 +146,8 @@ files:
133
146
  - lib/chronicle/spotify/listen_transformer.rb
134
147
  - lib/chronicle/spotify/listens_extractor.rb
135
148
  - lib/chronicle/spotify/proxy.rb
136
- - lib/chronicle/spotify/saved_albums_extractor.rb
149
+ - lib/chronicle/spotify/saved_album_extractor.rb
150
+ - lib/chronicle/spotify/saved_album_transformer.rb
137
151
  - lib/chronicle/spotify/spotify_extractor.rb
138
152
  - lib/chronicle/spotify/version.rb
139
153
  homepage: https://github.com/chronicle-app/chronicle-spotify
@@ -143,6 +157,7 @@ metadata:
143
157
  homepage_uri: https://github.com/chronicle-app/chronicle-spotify
144
158
  source_code_uri: https://github.com/chronicle-app/chronicle-spotify
145
159
  changelog_uri: https://github.com/chronicle-app/chronicle-spotify
160
+ rubygems_mfa_required: 'true'
146
161
  post_install_message:
147
162
  rdoc_options: []
148
163
  require_paths:
@@ -151,14 +166,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
151
166
  requirements:
152
167
  - - ">="
153
168
  - !ruby/object:Gem::Version
154
- version: '0'
169
+ version: '3.1'
155
170
  required_rubygems_version: !ruby/object:Gem::Requirement
156
171
  requirements:
157
172
  - - ">="
158
173
  - !ruby/object:Gem::Version
159
174
  version: '0'
160
175
  requirements: []
161
- rubygems_version: 3.3.3
176
+ rubygems_version: 3.4.10
162
177
  signing_key:
163
178
  specification_version: 4
164
179
  summary: Spotify importer for Chronicle
data/Gemfile.lock DELETED
@@ -1,190 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- chronicle-spotify (0.1.0)
5
- chronicle-etl (~> 0.5)
6
- omniauth-spotify
7
- rspotify (~> 2.11)
8
-
9
- GEM
10
- remote: https://rubygems.org/
11
- specs:
12
- activesupport (7.0.2.3)
13
- concurrent-ruby (~> 1.0, >= 1.0.2)
14
- i18n (>= 1.6, < 2)
15
- minitest (>= 5.1)
16
- tzinfo (~> 2.0)
17
- addressable (2.8.0)
18
- public_suffix (>= 2.0.2, < 5.0)
19
- ast (2.4.2)
20
- byebug (11.1.3)
21
- chronic_duration (0.10.6)
22
- numerizer (~> 0.1.1)
23
- chronicle-etl (0.5.3)
24
- activesupport (~> 7.0)
25
- chronic_duration (~> 0.10.6)
26
- colorize (~> 0.8.1)
27
- launchy
28
- marcel (~> 1.0.2)
29
- mini_exiftool (~> 2.10)
30
- nokogiri (~> 1.13)
31
- omniauth (~> 2)
32
- sequel (~> 5.35)
33
- sinatra (~> 2)
34
- sqlite3 (~> 1.4)
35
- thor (~> 1.2)
36
- thor-hollaback (~> 0.2)
37
- tty-progressbar (~> 0.17)
38
- tty-prompt (~> 0.23)
39
- tty-spinner
40
- tty-table (~> 0.11)
41
- xdg (>= 4.0)
42
- coderay (1.1.3)
43
- colorize (0.8.1)
44
- concurrent-ruby (1.1.10)
45
- domain_name (0.5.20190701)
46
- unf (>= 0.0.5, < 1.0.0)
47
- faraday (2.2.0)
48
- faraday-net_http (~> 2.0)
49
- ruby2_keywords (>= 0.0.4)
50
- faraday-net_http (2.0.2)
51
- hashie (5.0.0)
52
- hollaback (0.1.1)
53
- http-cookie (1.0.4)
54
- domain_name (~> 0.5)
55
- i18n (1.10.0)
56
- concurrent-ruby (~> 1.0)
57
- jwt (2.3.0)
58
- launchy (2.5.0)
59
- addressable (~> 2.7)
60
- marcel (1.0.2)
61
- method_source (1.0.0)
62
- mime-types (3.4.1)
63
- mime-types-data (~> 3.2015)
64
- mime-types-data (3.2022.0105)
65
- mini_exiftool (2.10.2)
66
- minitest (5.15.0)
67
- multi_json (1.15.0)
68
- multi_xml (0.6.0)
69
- mustermann (1.1.1)
70
- ruby2_keywords (~> 0.0.1)
71
- netrc (0.11.0)
72
- nokogiri (1.13.4-arm64-darwin)
73
- racc (~> 1.4)
74
- numerizer (0.1.1)
75
- oauth2 (1.4.9)
76
- faraday (>= 0.17.3, < 3.0)
77
- jwt (>= 1.0, < 3.0)
78
- multi_json (~> 1.3)
79
- multi_xml (~> 0.5)
80
- rack (>= 1.2, < 3)
81
- omniauth (2.1.0)
82
- hashie (>= 3.4.6)
83
- rack (>= 2.2.3)
84
- rack-protection
85
- omniauth-oauth2 (1.7.2)
86
- oauth2 (~> 1.4)
87
- omniauth (>= 1.9, < 3)
88
- omniauth-spotify (0.0.13)
89
- omniauth-oauth2 (~> 1.1)
90
- parallel (1.22.1)
91
- parser (3.1.2.0)
92
- ast (~> 2.4.1)
93
- pastel (0.8.0)
94
- tty-color (~> 0.5)
95
- pry (0.13.1)
96
- coderay (~> 1.1)
97
- method_source (~> 1.0)
98
- pry-byebug (3.9.0)
99
- byebug (~> 11.0)
100
- pry (~> 0.13.0)
101
- public_suffix (4.0.7)
102
- racc (1.6.0)
103
- rack (2.2.3)
104
- rack-protection (2.2.0)
105
- rack
106
- rainbow (3.1.1)
107
- rake (13.0.6)
108
- regexp_parser (2.3.0)
109
- rest-client (2.0.2)
110
- http-cookie (>= 1.0.2, < 2.0)
111
- mime-types (>= 1.16, < 4.0)
112
- netrc (~> 0.8)
113
- rexml (3.2.5)
114
- rspotify (2.11.1)
115
- addressable (~> 2.8.0)
116
- omniauth-oauth2 (>= 1.6)
117
- rest-client (~> 2.0.2)
118
- rubocop (1.27.0)
119
- parallel (~> 1.10)
120
- parser (>= 3.1.0.0)
121
- rainbow (>= 2.2.2, < 4.0)
122
- regexp_parser (>= 1.8, < 3.0)
123
- rexml
124
- rubocop-ast (>= 1.16.0, < 2.0)
125
- ruby-progressbar (~> 1.7)
126
- unicode-display_width (>= 1.4.0, < 3.0)
127
- rubocop-ast (1.17.0)
128
- parser (>= 3.1.1.0)
129
- ruby-progressbar (1.11.0)
130
- ruby2_keywords (0.0.5)
131
- sequel (5.55.0)
132
- sinatra (2.2.0)
133
- mustermann (~> 1.0)
134
- rack (~> 2.2)
135
- rack-protection (= 2.2.0)
136
- tilt (~> 2.0)
137
- sqlite3 (1.4.2)
138
- strings (0.2.1)
139
- strings-ansi (~> 0.2)
140
- unicode-display_width (>= 1.5, < 3.0)
141
- unicode_utils (~> 1.4)
142
- strings-ansi (0.2.0)
143
- thor (1.2.1)
144
- thor-hollaback (0.2.1)
145
- hollaback (~> 0.1)
146
- thor (>= 0.19.1)
147
- tilt (2.0.10)
148
- tty-color (0.6.0)
149
- tty-cursor (0.7.1)
150
- tty-progressbar (0.18.2)
151
- strings-ansi (~> 0.2)
152
- tty-cursor (~> 0.7)
153
- tty-screen (~> 0.8)
154
- unicode-display_width (>= 1.6, < 3.0)
155
- tty-prompt (0.23.1)
156
- pastel (~> 0.8)
157
- tty-reader (~> 0.8)
158
- tty-reader (0.9.0)
159
- tty-cursor (~> 0.7)
160
- tty-screen (~> 0.8)
161
- wisper (~> 2.0)
162
- tty-screen (0.8.1)
163
- tty-spinner (0.9.3)
164
- tty-cursor (~> 0.7)
165
- tty-table (0.12.0)
166
- pastel (~> 0.8)
167
- strings (~> 0.2.0)
168
- tty-screen (~> 0.8)
169
- tzinfo (2.0.4)
170
- concurrent-ruby (~> 1.0)
171
- unf (0.1.4)
172
- unf_ext
173
- unf_ext (0.0.8.1)
174
- unicode-display_width (2.1.0)
175
- unicode_utils (1.4.0)
176
- wisper (2.0.1)
177
- xdg (6.3.2)
178
-
179
- PLATFORMS
180
- arm64-darwin-20
181
-
182
- DEPENDENCIES
183
- bundler (~> 2.3)
184
- chronicle-spotify!
185
- pry-byebug (~> 3.9)
186
- rake (~> 13.0)
187
- rubocop
188
-
189
- BUNDLED WITH
190
- 2.3.8
@@ -1,17 +0,0 @@
1
- module Chronicle
2
- module Spotify
3
- class SavedAlbumsExtractor < Chronicle::Spotify::SpotifyExtractor
4
- register_connector do |r|
5
- r.provider = 'spotify'
6
- r.description = 'saved albums'
7
- r.identifier = 'saved-albums'
8
- end
9
-
10
- def extract
11
- @proxy.saved_albums(after: @config.since, limit: @config.limit) do |item|
12
- yield Chronicle::ETL::Extraction.new(data: item, meta: { actor: @actor })
13
- end
14
- end
15
- end
16
- end
17
- end