chronicle-spotify 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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